-
Notifications
You must be signed in to change notification settings - Fork 37
/
README.html
488 lines (389 loc) · 44.2 KB
/
README.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
<!DOCTYPE html>
<html>
<head>
<title>README</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="file:///C:\Users\yc9559\.vscode\extensions\shd101wyy.markdown-preview-enhanced-0.3.5\node_modules\@shd101wyy\mume\dependencies\katex\katex.min.css">
<style>
/**
* prism.js Github theme based on GitHub's theme.
* @author Sam Clarke
*/
code[class*="language-"],
pre[class*="language-"] {
color: #333;
background: none;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.4;
-moz-tab-size: 8;
-o-tab-size: 8;
tab-size: 8;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: .8em;
overflow: auto;
/* border: 1px solid #ddd; */
border-radius: 3px;
/* background: #fff; */
background: #f5f5f5;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
background: #f5f5f5;
}
.token.comment,
.token.blockquote {
color: #969896;
}
.token.cdata {
color: #183691;
}
.token.doctype,
.token.punctuation,
.token.variable,
.token.macro.property {
color: #333;
}
.token.operator,
.token.important,
.token.keyword,
.token.rule,
.token.builtin {
color: #a71d5d;
}
.token.string,
.token.url,
.token.regex,
.token.attr-value {
color: #183691;
}
.token.property,
.token.number,
.token.boolean,
.token.entity,
.token.atrule,
.token.constant,
.token.symbol,
.token.command,
.token.code {
color: #0086b3;
}
.token.tag,
.token.selector,
.token.prolog {
color: #63a35c;
}
.token.function,
.token.namespace,
.token.pseudo-element,
.token.class,
.token.class-name,
.token.pseudo-class,
.token.id,
.token.url-reference .token.variable,
.token.attr-name {
color: #795da3;
}
.token.entity {
cursor: help;
}
.token.title,
.token.title .token.punctuation {
font-weight: bold;
color: #1d3e81;
}
.token.list {
color: #ed6a43;
}
.token.inserted {
background-color: #eaffea;
color: #55a532;
}
.token.deleted {
background-color: #ffecec;
color: #bd2c00;
}
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
/* JSON */
.language-json .token.property {
color: #183691;
}
.language-markup .token.tag .token.punctuation {
color: #333;
}
/* CSS */
code.language-css,
.language-css .token.function {
color: #0086b3;
}
/* YAML */
.language-yaml .token.atrule {
color: #63a35c;
}
code.language-yaml {
color: #183691;
}
/* Ruby */
.language-ruby .token.function {
color: #333;
}
/* Markdown */
.language-markdown .token.url {
color: #795da3;
}
/* Makefile */
.language-makefile .token.symbol {
color: #795da3;
}
.language-makefile .token.variable {
color: #183691;
}
.language-makefile .token.builtin {
color: #0086b3;
}
/* Bash */
.language-bash .token.keyword {
color: #0086b3;
}html body{font-family:"Helvetica Neue",Helvetica, "PingFang SC", "Microsoft YaHei", "Segoe UI",Arial,freesans,sans-serif;font-size:16px;line-height:1.6;color:#333;background-color:#fff;overflow:initial;box-sizing:border-box;word-wrap:break-word}html body>:first-child{margin-top:0}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{line-height:1.2;margin-top:1em;margin-bottom:16px;color:#000}html body h1{font-size:2.25em;font-weight:300;padding-bottom:.3em}html body h2{font-size:1.75em;font-weight:400;padding-bottom:.3em}html body h3{font-size:1.5em;font-weight:500}html body h4{font-size:1.25em;font-weight:600}html body h5{font-size:1.1em;font-weight:600}html body h6{font-size:1em;font-weight:600}html body h1,html body h2,html body h3,html body h4,html body h5{font-weight:600}html body h5{font-size:1em}html body h6{color:#5c5c5c}html body strong{color:#000}html body del{color:#5c5c5c}html body a:not([href]){color:inherit;text-decoration:none}html body a{color:#08c;text-decoration:none}html body a:hover{color:#00a3f5;text-decoration:none}html body img{max-width:100%}html body>p{margin-top:0;margin-bottom:16px;word-wrap:break-word}html body>ul,html body>ol{margin-bottom:16px}html body ul,html body ol{padding-left:2em}html body ul.no-list,html body ol.no-list{padding:0;list-style-type:none}html body ul ul,html body ul ol,html body ol ol,html body ol ul{margin-top:0;margin-bottom:0}html body li{margin-bottom:0}html body li.task-list-item{list-style:none}html body li>p{margin-top:0;margin-bottom:0}html body .task-list-item-checkbox{margin:0 .2em .25em -1.8em;vertical-align:middle}html body .task-list-item-checkbox:hover{cursor:pointer}html body blockquote{margin:16px 0;font-size:inherit;padding:0 15px;color:#5c5c5c;border-left:4px solid #d6d6d6}html body blockquote>:first-child{margin-top:0}html body blockquote>:last-child{margin-bottom:0}html body hr{height:4px;margin:32px 0;background-color:#d6d6d6;border:0 none}html body table{margin:10px 0 15px 0;border-collapse:collapse;border-spacing:0;display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}html body table th{font-weight:bold;color:#000}html body table td,html body table th{border:1px solid #d6d6d6;padding:6px 13px}html body dl{padding:0}html body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:bold}html body dl dd{padding:0 16px;margin-bottom:16px}html body code{font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:.85em !important;color:#000;background-color:#f0f0f0;border-radius:3px;padding:.2em 0}html body code::before,html body code::after{letter-spacing:-0.2em;content:"\00a0"}html body pre>code{padding:0;margin:0;font-size:.85em !important;word-break:normal;white-space:pre;background:transparent;border:0}html body .highlight{margin-bottom:16px}html body .highlight pre,html body pre{padding:1em;overflow:auto;font-size:.85em !important;line-height:1.45;border:#d6d6d6;border-radius:3px}html body .highlight pre{margin-bottom:0;word-break:normal}html body pre code,html body pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}html body pre code:before,html body pre tt:before,html body pre code:after,html body pre tt:after{content:normal}html body p,html body blockquote,html body ul,html body ol,html body dl,html body pre{margin-top:0;margin-bottom:16px}html body kbd{color:#000;border:1px solid #d6d6d6;border-bottom:2px solid #c7c7c7;padding:2px 4px;background-color:#f0f0f0;border-radius:3px}@media print{html body{background-color:#fff}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{color:#000;page-break-after:avoid}html body blockquote{color:#5c5c5c}html body pre{page-break-inside:avoid}html body table{display:table}html body img{display:block;max-width:100%;max-height:100%}html body pre,html body code{word-wrap:break-word;white-space:pre}}.markdown-preview{width:100%;height:100%;box-sizing:border-box}.markdown-preview .pagebreak,.markdown-preview .newpage{page-break-before:always}.markdown-preview pre.line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}.markdown-preview pre.line-numbers>code{position:relative}.markdown-preview pre.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:1em;font-size:100%;left:0;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.markdown-preview pre.line-numbers .line-numbers-rows>span{pointer-events:none;display:block;counter-increment:linenumber}.markdown-preview pre.line-numbers .line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}.markdown-preview .mathjax-exps .MathJax_Display{text-align:center !important}.markdown-preview:not([for="preview"]) .code-chunk .btn-group{display:none}.markdown-preview:not([for="preview"]) .code-chunk .status{display:none}.markdown-preview:not([for="preview"]) .code-chunk .output-div{margin-bottom:16px}.scrollbar-style::-webkit-scrollbar{width:8px}.scrollbar-style::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}.scrollbar-style::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,0.66);border:4px solid rgba(150,150,150,0.66);background-clip:content-box}html body[for="html-export"]:not([data-presentation-mode]){position:relative;width:100%;height:100%;top:0;left:0;margin:0;padding:0;overflow:auto}html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{position:relative;top:0}@media screen and (min-width:914px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{padding:2em calc(50% - 457px)}}@media screen and (max-width:914px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{font-size:14px !important;padding:1em}}@media print{html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn{display:none}}html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn{position:fixed;bottom:8px;left:8px;font-size:28px;cursor:pointer;color:inherit;z-index:99;width:32px;text-align:center;opacity:.4}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] #sidebar-toc-btn{opacity:1}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc{position:fixed;top:0;left:0;width:300px;height:100%;padding:32px 0 48px 0;font-size:14px;box-shadow:0 0 4px rgba(150,150,150,0.33);box-sizing:border-box;overflow:auto;background-color:inherit}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar{width:8px}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,0.66);border:4px solid rgba(150,150,150,0.66);background-clip:content-box}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc a{text-decoration:none}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc ul{padding:0 1.6em;margin-top:.8em}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc li{margin-bottom:.8em}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc ul{list-style-type:none}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{left:300px;width:calc(100% - 300px);padding:2em calc(50% - 457px - 150px);margin:0;box-sizing:border-box}@media screen and (max-width:1274px){html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{width:100%}}html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .markdown-preview{left:50%;transform:translateX(-50%)}html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .md-sidebar-toc{display:none}
</style>
</head>
<body for="html-export">
<div class="mume markdown-preview ">
<h1 class="mume-header" id="%CE%BCcos-ii-for-visual-studio-2017">μC/OS-II for Visual Studio 2017</h1>
<p>修改自Micrium官网适配给VS2017源码,加入卢有亮的《嵌入式实时操作系统μC/OS原理与实践》移植代码中的实验例子。</p>
<h2 class="mume-header" id="%E5%8C%85%E5%90%AB%E7%9A%84-micrium-%E4%BA%A7%E5%93%81%E7%89%88%E6%9C%AC">包含的 MICRIUM 产品版本</h2>
<ul>
<li>uC/OS-II v2.92.13</li>
<li>uC/OS-III v3.06.02</li>
<li>uC/CPU v1.31.01</li>
<li>uC/LIB v1.38.02</li>
</ul>
<h2 class="mume-header" id="ide-%E7%8E%AF%E5%A2%83%E8%A6%81%E6%B1%82">IDE 环境要求</h2>
<ul>
<li>Visual Studio v2017</li>
</ul>
<h2 class="mume-header" id="vs%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E6%96%87%E4%BB%B6%E8%B7%AF%E5%BE%84">VS解决方案文件路径</h2>
<ul>
<li>Microsoft/Windows/Kernel/OS2/VS/OS2.sln</li>
<li>Microsoft/Windows/Kernel/OS3/VS/OS3.sln</li>
</ul>
<h2 class="mume-header" id="%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E">使用说明</h2>
<ol>
<li>在 Visual Studio 打开上面路径的文件</li>
<li>在项目上点右键,清理已编译的文件</li>
<li>修改<code>Windows SDK Version</code>为可用的版本,比如<code>10.0.17134.0</code></li>
<li>编译并运行</li>
</ol>
<p><img src="./media/vs2017_sdk.png" alt="vs2017 sdk"></p>
<h2 class="mume-header" id="%E5%8E%9F%E5%A7%8B%E9%93%BE%E6%8E%A5">原始链接</h2>
<p><a href="https://www.micrium.com/download/micrium_win32_kernel/">https://www.micrium.com/download/micrium_win32_kernel/</a></p>
<h2 class="mume-header" id="%E7%A7%BB%E6%A4%8D%E5%AE%9E%E7%8E%B0%E6%A6%82%E8%BF%B0">移植实现概述</h2>
<blockquote>
<p>注意以下代码做了大量删改,仅保留主线部分</p>
</blockquote>
<h3 class="mume-header" id="%E6%97%B6%E9%97%B4%E7%89%87">时间片</h3>
<p>时间片依赖于定时器对响应代码的定期唤醒。<br>
传统硬件平台的定时器来源是硬件定时器,软件模拟定时器来源是Windows Multimedia API提供的服务中的<code>timeSetEvent</code>。<br>
Windows Multimedia API的入口在<code>winmm.dll</code>,因此工程环境应该引入这个动态库的依赖。</p>
<p>位于<code>os_cpu_c.c</code>中的<code>OSInitHookBegin()</code></p>
<pre data-role="codeBlock" data-info="c" class="language-c"><span class="token keyword">void</span> <span class="token function">OSInitHookBegin</span> <span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token comment">// 将OSTickW32绑定到一个线程上,并把线程ID写到OSTick_ThreadId</span>
OSTick_Thread <span class="token operator">=</span> <span class="token function">CreateThread</span><span class="token punctuation">(</span><span class="token constant">NULL</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> OSTickW32<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> CREATE_SUSPENDED<span class="token punctuation">,</span> <span class="token operator">&</span>OSTick_ThreadId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//在整个进程里这个线程能被最优先运行,时间片服务能够被及时运行</span>
<span class="token function">SetThreadPriority</span><span class="token punctuation">(</span>OSTick_Thread<span class="token punctuation">,</span> THREAD_PRIORITY_HIGHEST<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//设定的OSTick_TimerCap应该大于等于winmm提供的最大时间精度(最小时间间隔)</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>OSTick_TimerCap<span class="token punctuation">.</span>wPeriodMin <span class="token operator"><</span> WIN_MM_MIN_RES<span class="token punctuation">)</span> <span class="token punctuation">{</span>
OSTick_TimerCap<span class="token punctuation">.</span>wPeriodMin <span class="token operator">=</span> WIN_MM_MIN_RES<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 设置这个精度</span>
<span class="token function">timeBeginPeriod</span><span class="token punctuation">(</span>OSTick_TimerCap<span class="token punctuation">.</span>wPeriodMin<span class="token punctuation">)</span>;
<span class="token comment">// 创建事件,可以理解为通知,通过setEvent给等待这个事件/通知的线程设置为可运行</span>
OSTick_SignalPtr <span class="token operator">=</span> <span class="token function">CreateEvent</span><span class="token punctuation">(</span><span class="token constant">NULL</span><span class="token punctuation">,</span> TRUE<span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 设置循环定时触发的周期,精度,触发时操作OSTick_SignalPtr</span>
OSTick_TimerId <span class="token operator">=</span> <span class="token function">timeSetEvent</span><span class="token punctuation">(</span><span class="token punctuation">(</span>UINT <span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">1000u</span> <span class="token operator">/</span> OS_TICKS_PER_SEC<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">(</span>UINT <span class="token punctuation">)</span> OSTick_TimerCap<span class="token punctuation">.</span>wPeriodMin<span class="token punctuation">,</span>
<span class="token punctuation">(</span>LPTIMECALLBACK<span class="token punctuation">)</span> OSTick_SignalPtr<span class="token punctuation">,</span>
<span class="token punctuation">(</span>DWORD_PTR <span class="token punctuation">)</span> <span class="token constant">NULL</span><span class="token punctuation">,</span>
<span class="token punctuation">(</span>UINT <span class="token punctuation">)</span><span class="token punctuation">(</span>TIME_PERIODIC <span class="token operator">|</span> TIME_CALLBACK_EVENT_SET<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span>
</pre><p>在上面的代码里,创建了<code>OSTick_Thread</code>,设置好了winmm提供的循环定时触发,定时触发的时间片服务函数等待的事件。<br>
为了让<code>OSTick_Thread</code>能定时唤醒,<code>OSTickW32()</code>内应该有死循环以及等待<code>OSTick_SignalPtr</code>事件。</p>
<pre data-role="codeBlock" data-info="c" class="language-c"><span class="token keyword">static</span> DWORD WINAPI <span class="token function">OSTickW32</span> <span class="token punctuation">(</span>LPVOID p_arg<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
CPU_BOOLEAN terminate<span class="token punctuation">;</span>
CPU_BOOLEAN suspended<span class="token punctuation">;</span>
HANDLE wait_signal<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token function">CPU_SR_ALLOC</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 等待OSTick_SignalPtr事件,以及等待系统终止的事件</span>
wait_signal<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> OSTerminate_SignalPtr<span class="token punctuation">;</span>
wait_signal<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> OSTick_SignalPtr<span class="token punctuation">;</span>
terminate <span class="token operator">=</span> DEF_FALSE<span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>terminate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span><span class="token function">WaitForMultipleObjects</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> wait_signal<span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> INFINITE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// OSTick_SignalPtr 触发了</span>
<span class="token keyword">case</span> WAIT_OBJECT_0 <span class="token operator">+</span> <span class="token number">1u</span><span class="token punctuation">:</span>
<span class="token comment">// 重置一下这个事件,为下次触发准备</span>
<span class="token function">ResetEvent</span><span class="token punctuation">(</span>OSTick_SignalPtr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 更改进程状态,关中断</span>
<span class="token function">CPU_CRITICAL_ENTER</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
suspended <span class="token operator">=</span> <span class="token function">OSIntCurTaskSuspend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 完成时间片更新的一些事</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>suspended <span class="token operator">==</span> DEF_TRUE<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">OSIntEnter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">OSTimeTick</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">OSIntExit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">OSIntCurTaskResume</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">CPU_CRITICAL_EXIT</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</pre><h3 class="mume-header" id="%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86">进程管理</h3>
<p>进程管理依赖于底层的上下文切换。<br>
传统硬件平台的上下文切换基本是寄存器入栈备份现场,任务堆栈出栈还原现场。<br>
这里的上下文切换,依赖于操作系统提供的进程内线程切换,线程切换自带了上下文切换。<br>
为了把μC/OS内的进程给操作系统作为线程管理,需要包装一下。</p>
<pre data-role="codeBlock" data-info="c" class="language-c"><span class="token keyword">typedef</span> <span class="token keyword">struct</span> os_task_stk <span class="token punctuation">{</span>
<span class="token keyword">void</span> <span class="token operator">*</span>TaskArgPtr<span class="token punctuation">;</span> <span class="token comment">/* Task 参数数组指针 */</span>
INT16U TaskOpt<span class="token punctuation">;</span> <span class="token comment">/* Task 选项 */</span>
<span class="token keyword">void</span> <span class="token punctuation">(</span><span class="token operator">*</span>Task<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Task 函数入口 */</span>
HANDLE ThreadHandle<span class="token punctuation">;</span> <span class="token comment">/* Task 线程的句柄 */</span>
DWORD ThreadID<span class="token punctuation">;</span> <span class="token comment">/* Task 线程的线程ID */</span>
<span class="token keyword">volatile</span> OS_TASK_STATE TaskState<span class="token punctuation">;</span> <span class="token comment">/* Task 线程的状态 */</span>
HANDLE SignalPtr<span class="token punctuation">;</span> <span class="token comment">/* Task 线程的同步 信号 */</span>
HANDLE InitSignalPtr<span class="token punctuation">;</span> <span class="token comment">/* Task 线程的创建 信号 */</span>
CPU_BOOLEAN Terminate<span class="token punctuation">;</span> <span class="token comment">/* Task 线程的结束 标志 */</span>
OS_TCB <span class="token operator">*</span>OSTCBPtr<span class="token punctuation">;</span> <span class="token comment">/* Task TCB指针 */</span>
<span class="token punctuation">}</span> OS_TASK_STK<span class="token punctuation">;</span>
</pre><p>在这个数据结构里,存储TCB外包装的线程各种信息,由于这些信息存储在它的任务堆栈里,它的赋初值在TCB初始化的任务堆栈初始化里完成。</p>
<pre data-role="codeBlock" data-info="c" class="language-c">OS_STK <span class="token operator">*</span><span class="token function">OSTaskStkInit</span> <span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token punctuation">(</span><span class="token operator">*</span>task<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span>pd<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>p_arg<span class="token punctuation">,</span> OS_STK <span class="token operator">*</span>ptos<span class="token punctuation">,</span> INT16U opt<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
OS_TASK_STK <span class="token operator">*</span>p_stk<span class="token punctuation">;</span>
<span class="token comment">/* Load stack pointer */</span>
p_stk <span class="token operator">=</span> <span class="token punctuation">(</span>OS_TASK_STK <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span>ptos <span class="token operator">-</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>OS_TASK_STK<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>TaskArgPtr <span class="token operator">=</span> p_arg<span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>TaskOpt <span class="token operator">=</span> opt<span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>Task <span class="token operator">=</span> task<span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>ThreadHandle <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>ThreadID <span class="token operator">=</span> <span class="token number">0u</span><span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>TaskState <span class="token operator">=</span> STATE_NONE<span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>SignalPtr <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>InitSignalPtr <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>Terminate <span class="token operator">=</span> DEF_FALSE<span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>OSTCBPtr <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>OS_STK <span class="token operator">*</span><span class="token punctuation">)</span>p_stk<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</pre><p>在<code>OSTaskStkInit()</code>随后执行的<code>OS_TCBInit()</code>里,借助<code>OSTCBInitHook(ptcb);</code>里完成对该task的外包装进一步初始化。</p>
<pre data-role="codeBlock" data-info="c" class="language-c"><span class="token keyword">void</span> <span class="token function">OSTCBInitHook</span> <span class="token punctuation">(</span>OS_TCB <span class="token operator">*</span>p_tcb<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
OS_TASK_STK <span class="token operator">*</span>p_stk<span class="token punctuation">;</span>
p_stk <span class="token operator">=</span> <span class="token punctuation">(</span>OS_TASK_STK <span class="token operator">*</span><span class="token punctuation">)</span>p_tcb<span class="token operator">-></span>OSTCBStkPtr<span class="token punctuation">;</span>
<span class="token comment">// Task 线程的同步信号,实际上切换到这个任务的线程就是靠这个事件通知的</span>
p_stk<span class="token operator">-></span>SignalPtr <span class="token operator">=</span> <span class="token function">CreateEvent</span><span class="token punctuation">(</span><span class="token constant">NULL</span><span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Task 线程的创建完成信号,</span>
p_stk<span class="token operator">-></span>InitSignalPtr <span class="token operator">=</span> <span class="token function">CreateEvent</span><span class="token punctuation">(</span><span class="token constant">NULL</span><span class="token punctuation">,</span> TRUE<span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Task 线程的句柄,把OSTaskW32这个任务包装函数绑定到线程</span>
p_stk<span class="token operator">-></span>ThreadHandle <span class="token operator">=</span> <span class="token function">CreateThread</span><span class="token punctuation">(</span><span class="token constant">NULL</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> OSTaskW32<span class="token punctuation">,</span> p_tcb<span class="token punctuation">,</span> CREATE_SUSPENDED<span class="token punctuation">,</span> <span class="token operator">&</span>p_stk<span class="token operator">-></span>ThreadID<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 设置以下当前状态,创建完毕但还没运行过</span>
p_stk<span class="token operator">-></span>TaskState <span class="token operator">=</span> STATE_CREATED<span class="token punctuation">;</span>
p_stk<span class="token operator">-></span>OSTCBPtr <span class="token operator">=</span> p_tcb<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</pre><p>还差一点,task的内部函数就可以开始运行了。在任务调度开始之后,完成下面的这一点工作。<br>
顺序为:<code>OSTCBInitHook()</code>-><code>OSCtxSw()</code>-><code>OSTaskW32()</code>-><code>OSCtxSw()</code>-><code>OSTaskW32()</code>->END</p>
<pre data-role="codeBlock" data-info="c" class="language-c"><span class="token keyword">static</span> DWORD WINAPI <span class="token function">OSTaskW32</span> <span class="token punctuation">(</span>LPVOID p_arg<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
OS_TASK_STK <span class="token operator">*</span>p_stk<span class="token punctuation">;</span>
OS_TCB <span class="token operator">*</span>p_tcb<span class="token punctuation">;</span>
p_tcb <span class="token operator">=</span> <span class="token punctuation">(</span>OS_TCB <span class="token operator">*</span><span class="token punctuation">)</span>p_arg<span class="token punctuation">;</span>
p_stk <span class="token operator">=</span> <span class="token punctuation">(</span>OS_TASK_STK <span class="token operator">*</span><span class="token punctuation">)</span>p_tcb<span class="token operator">-></span>OSTCBStkPtr<span class="token punctuation">;</span>
<span class="token comment">// 等待task被首次被调度到,等到了再往后执行</span>
<span class="token comment">// 这个等待,使得回到前面执行OSCtxSw的线程上</span>
p_stk<span class="token operator">-></span>TaskState <span class="token operator">=</span> STATE_SUSPENDED<span class="token punctuation">;</span>
<span class="token function">WaitForSingleObject</span><span class="token punctuation">(</span>p_stk<span class="token operator">-></span>SignalPtr<span class="token punctuation">,</span> INFINITE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 给线程设置个名字,便于IDE调试</span>
<span class="token function">OSSetThreadName</span><span class="token punctuation">(</span>p_stk<span class="token operator">-></span>ThreadID<span class="token punctuation">,</span> p_tcb<span class="token operator">-></span>OSTCBTaskName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 等待到了,标记任务已经初始化完毕,准备好被正式调度了</span>
p_stk<span class="token operator">-></span>TaskState <span class="token operator">=</span> STATE_RUNNING<span class="token punctuation">;</span>
<span class="token function">SetEvent</span><span class="token punctuation">(</span>p_stk<span class="token operator">-></span>InitSignalPtr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 执行task的函数</span>
p_stk<span class="token operator">-></span><span class="token function">Task</span><span class="token punctuation">(</span>p_stk<span class="token operator">-></span>TaskArgPtr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 如果上面的函数执行完毕返回了,就要删除自己</span>
<span class="token function">OSTaskDel</span><span class="token punctuation">(</span>p_tcb<span class="token operator">-></span>OSTCBPrio<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token number">0u</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</pre><pre data-role="codeBlock" data-info="c" class="language-c"><span class="token keyword">void</span> <span class="token function">OSCtxSw</span> <span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
OS_TASK_STK <span class="token operator">*</span>p_stk<span class="token punctuation">;</span>
OS_TASK_STK <span class="token operator">*</span>p_stk_new<span class="token punctuation">;</span>
<span class="token function">CPU_SR_ALLOC</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
p_stk <span class="token operator">=</span> <span class="token punctuation">(</span>OS_TASK_STK <span class="token operator">*</span><span class="token punctuation">)</span>OSTCBCur<span class="token operator">-></span>OSTCBStkPtr<span class="token punctuation">;</span>
<span class="token function">OSTaskSwHook</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
OSTCBCur <span class="token operator">=</span> OSTCBHighRdy<span class="token punctuation">;</span>
OSPrioCur <span class="token operator">=</span> OSPrioHighRdy<span class="token punctuation">;</span>
<span class="token comment">// 当前的老任务状态位改为挂起,但是没有入栈这个操作,因为保存上下文由做线程切换的操作系统完成</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>p_stk<span class="token operator">-></span>TaskState <span class="token operator">==</span> STATE_RUNNING<span class="token punctuation">)</span> <span class="token punctuation">{</span>
p_stk<span class="token operator">-></span>TaskState <span class="token operator">=</span> STATE_SUSPENDED<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
p_stk_new <span class="token operator">=</span> <span class="token punctuation">(</span>OS_TASK_STK <span class="token operator">*</span><span class="token punctuation">)</span>OSTCBHighRdy<span class="token operator">-></span>OSTCBStkPtr<span class="token punctuation">;</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>p_stk_new<span class="token operator">-></span>TaskState<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> STATE_CREATED<span class="token punctuation">:</span>
<span class="token comment">// 刚创建好,需要OSTaskW32()来进一步初始化</span>
<span class="token function">ResumeThread</span><span class="token punctuation">(</span>p_stk_new<span class="token operator">-></span>ThreadHandle<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 等待这个任务的初始化完毕的事件,然后设置SignalPtr这个事件使得这个task的线程处于就绪</span>
<span class="token comment">// 原型:SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, dwMilliseconds, bAlertable);</span>
<span class="token function">SignalObjectAndWait</span><span class="token punctuation">(</span>p_stk_new<span class="token operator">-></span>SignalPtr<span class="token punctuation">,</span> p_stk_new<span class="token operator">-></span>InitSignalPtr<span class="token punctuation">,</span> INFINITE<span class="token punctuation">,</span> FALSE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> STATE_SUSPENDED<span class="token punctuation">:</span>
<span class="token comment">// 设置SignalPtr这个事件,这个task的线程处于就绪</span>
p_stk_new<span class="token operator">-></span>TaskState <span class="token operator">=</span> STATE_RUNNING<span class="token punctuation">;</span>
<span class="token function">SetEvent</span><span class="token punctuation">(</span>p_stk_new<span class="token operator">-></span>SignalPtr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> STATE_INTERRUPTED<span class="token punctuation">:</span>
p_stk_new<span class="token operator">-></span>TaskState <span class="token operator">=</span> STATE_RUNNING<span class="token punctuation">;</span>
<span class="token function">ResumeThread</span><span class="token punctuation">(</span>p_stk_new<span class="token operator">-></span>ThreadHandle<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">default</span><span class="token punctuation">:</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>p_stk<span class="token operator">-></span>Terminate <span class="token operator">==</span> DEF_TRUE<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">OSTaskTerminate</span><span class="token punctuation">(</span>p_stk<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">CPU_CRITICAL_EXIT</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/* ExitThread() never returns. */</span>
<span class="token function">ExitThread</span><span class="token punctuation">(</span><span class="token number">0u</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">CPU_CRITICAL_EXIT</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 究竟是谁在等待SignalPtr这个事件,难道不是做一些切换的事情吗</span>
<span class="token function">WaitForSingleObject</span><span class="token punctuation">(</span>p_stk<span class="token operator">-></span>SignalPtr<span class="token punctuation">,</span> INFINITE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">CPU_CRITICAL_ENTER</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</pre><p>线程切换肯定是把控制权给等待这个型号的线程,自己等自己是为什么呢?<br>
于是看了下线程的函数调用堆栈:</p>
<p><img src="./media/tcb-thread-stack.png" alt="thread-stack"></p>
<p>这是在等其他线程,设置自己线程的<code>SignalPtr</code>,让自己线程继续运行。</p>
</div>
</body>
</html>