① githubmarkdown以源码方式显示了
注意:Windows环境下载时,分为User版和System版(推荐),User版只能安装在C盘的用户文件夹下,System版可以自定义安装位置,用户可以安装需求选择下载哪个版本。
设置中文
安装好VS Code后,软件默认为英文,以下步骤可以将其设置为中文。
选择View - Command Palette,或使用快捷键Ctrl+Shift+P,搜索configure language,然后选择Configure Display Language,然后选择zh-cn,如下图。
在这里插入图片描述
注意: 若选择Configure Display Language后,未出现上图所示选项,而是出现如下图的json文件编辑页面,则可能为旧版的VS Code,将json文件中的locale后面的en改为zh-cn,然后按照步骤3中安装Chinese (Simplified)Language Pack扩展。
在这里插入图片描述
若没有zh-cn,可以选择Install additional languages,然后安装扩展包Chinese (Simplified) Language Pack,然后重复步骤1。
也可以先在View - Extensions中安装Chinese (Simplified)Language Pack中文简体语言包扩展,如下图第1个扩展,然后进行步骤1。
在这里插入图片描述
安装扩展
在查看 - 扩展中可以查看、设置、启用、禁用、卸载已安装扩展,即对已安装扩展进行管理,同时可以搜索并安装各种扩展,如下图。
在这里插入图片描述
编辑Markdown文档
在VS Code中打开或新建.md格式的文件即可进行编辑(在VS Code中新建文件时可能需要先保存为.md格式文件),点击右上角的预览按钮可以进行实时预览。下图第一个按钮即为预览按钮。
在这里插入图片描述
配合Markdown使用的扩展
推荐的扩展套装:
基于Markdown Preview Enhanced扩展预览窗口(推荐):Markdown Preview Enhanced 和 Prince软件 + markdownlint + Mermaid Markdown Syntax Highlighting + Maridown pdf(可选) + vscode-pdf(可选)
优点:支持各种CSDN博客特殊语法,如:mermaid绘图,注脚,注释,等等。而且预览窗口不受VS Code软件深色主题的影响,更加形象的展示所编写文件的pdf文档样式。
基于原生预览窗口:markdownlint + Markdown+Math + Mermaid Markdown Syntax Highlighting + Markdown Preview Mermaid Support + Maridown PDF + vscode-pdf(可选)
优点:预览窗口反应快速,无需安装额外的预览扩展,主题可以跟随VS Code软件的深色主题。
缺点:部分特殊语法无法得到支持。
以下为各个扩展的详情介绍:
markdownlint:一个好用的 Markdown 格式检查扩展,它规定了许多规则并实时对文档进行检查,防止一些语法错误,同时维持文档风格的统一,使用此工具有助于形成一个良好的写作习惯和规范。
Markdown Preview Enhanced:一个很好用的完善预览功能的插件,可以更加形象的展示所编写文件的pdf文档样式。优点是支持LaTeX数学公式和Mermaid图表等内容的显示。
安装后,你会发现工作区的右上角多了一个预览按钮,这个按钮就是Markdown Preview Enhanced插件产生的,如下图。直接右键.md文件的页面也可以开启Markdown Preview Enhanced。
在这里插入图片描述
注意:右键Markdown Preview Enhanced预览页面也有一些选项,如下图。Open in Browser是在浏览器中打开预览,HTML是打印成HTML文件,PDF是打印成PDF文件(此选项需额外安装Prince软件,VS Code扩展库中没有,安装方法见后文)。
在这里插入图片描述
安装Prince软件:进入Prince官网,点击下载,选择对应的版本进行下载并安装。然后添加环境变量,右键我的电脑->属性->高级系统设置->环境变量->系统变量->Path->编辑,新建一条Prince安装路径\engine\bin即可。然后重启VS Code。
Markdown All in One:集成了各种功能,同时也支持LaTeX数学公式(在扩展设置中启用基本的数学支持选项可以开启与关闭该功能),但貌似没有显示Mermaid图表和打印PDF的功能。个人建议,若启用Markdown+Math扩展,则不必启用此扩展。
Markdown+Math:使VS Code原生的Markdown预览窗口支持显示LaTeX数学公式。可以与Markdown All in One扩展同时使用,同时使用时,LaTeX公式显示风格以Markdown+Math为标准。
Mermaid Markdown Syntax Highlighting:支持Mermaid图表代码高亮,但无法在原生预览窗口显示。
Markdown Preview Mermaid Support:支持原生预览窗口显示Mermaid图表。
Maridown PDF:可以简单的将编写的.md文件转换成其他格式的文件,右键.md文件的页面可以进行转换,如下图。生成的文件将会直接保存在.md文件的文件夹下。但不支持LaTeX数学公式和Mermaid图表等内容的显示。
在这里插入图片描述
vscode-pdf:若希望在VS Code中直接打开并浏览pdf格式文件,可以通过安装该插件来达到该目的。
Markdown Pad 2
介绍
Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。而Markdown Pad 2 便是编辑Markdown语言的一款编辑器,其功能强大,便捷,速度快,无广告,而且还可以进行个性化设置。下面介绍一下Windows系统下,该工具的安装与配置方法。
安装
进入官网:官网链接,然后点击Download MarkdownPad;或者直接点击该链接,下载链接,会立刻开始下载。
运行上一步骤下载到的exe文件,开始安装,并完成安装。
注意:Win10若提示HTML渲染组件出错,错误的表现形式为,不能实时预览Markdown生成的HTML页面。则需要安装awesomium_sdk,下载地址:Download awesomium_v1.6.6_sdk_win.exe。
设置中文
Tool —> Options —> Editor —> Language,选择中文。
Key
在初次打开软件时单击Enter Key按钮,或点击帮助—>升级到MarkdownPad专业版。输入如下Email和Key。
Email
[email protected]
1
1
Key
/sQytXJUQl/D8Vb/ikJdhGMMQr0R4B+L3nWU97eaVPTRKfWGDE8/eAgKzpGwrQQoDh+nzX1xoVQ8NAuH+s4UcSeQ==
1
1
个性化设置
菜单栏 —> 工具 —> 选项
Markdown —> GitHub 风格 Markdown (离线)
样式表 —> Markdownpad-github.css
文件 —> 在导出的PDF文件中包含CSS背景
Markdown与HTML的联系
Markdown支持HTML的大部分标签,但反之HTML不支持Markdown语法;即Markdown兼容HTML。例如换行标签<br>,键盘文本<kbd>,预格式文本<pre>,上标<sup>,下标<sub>,等等。更多标签和用法请参照HTML标签 。
例子:
键盘文本-复制的快捷键:<kbd>Ctrl/Command</kbd> + <kbd>C</kbd>
显示:
Ctrl/Command + C
Markdown中支持HTML的大部分字符实体,如大于号:> ,显示为>。更多HTML字符实体请参照HTML字符实体 。
编辑技巧
快捷键
在编辑页面可以适当的使用快捷键提升效率。以下为CSDN的快捷键,其中有些是可以通用于各个编辑器的。
CSDN快捷键:
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
待办列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
列表
当使用顺序列表时,按回车会自动生成序号,想中断排序,再按一次回车即可。
在顺序列表的编号后面按回车,不会打乱编号的顺序。
当使用列表后,缩进中断时,可以使用Tab进行缩进。
标记失效
在使用Markdown标记语言时,一些标记后需要加空格才会生效,如标题标记:# 。
一些标记的前面需要有回车才会生效,如分隔符:--- 。
一些字体标记,当结束标记前的字符为标点符号时可能会失效。
例如:**标点符号。**是句号。
显示:**标点符号。**是句号。
解决方案:在结束标记**后加空格即可,其他字体标记同理。
例如:**标点符号。** 是句号。
显示:标点符号。 是句号。
页面内跳转
由于Markdown目前没有实现页面内跳转的方法,故可以使用HTML的方法进行页面内跳转,因为Markdown支持HTML。值得一提的是,跳转到锚点时,可以使用Markdown的链接语法进行跳转。
注意: 示例中锚点的<h1>标签可以换成任何其他标签,如<text>标签等。
纯HTML示例:
<!-- 跳转到锚点 -->
<a href="#1">锚点目标</a>
<!-- 创建锚点 -->
<h1 id="1">锚点</h1>
1
2
3
4
1
2
3
4
HTML创建锚点+Markdown跳转示例:
跳转到锚点:[锚点目标](锚点id '标题')
创建锚点(同上):<h1 id="1">锚点</h1>
展示:
HTML语法跳转:锚点目标
Markdown语法跳转:锚点目标
锚点
CSDN博客技巧
CSDN目录
输入#,并按下Space后,将生成1级标题。
输入##,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用@[TOC](自定义目录标题)或@[toc](自定义目录标题)语法后生成一个有缩进的目录,可实现页内跳转。
CSDN快捷键
同编辑技巧章节的快捷键。此处省略。
自定义列表
CSDN编辑器支持,某些本地编辑器不支持。
例子(最前面要有空行):
Authors
: John
: Luke
1
2
3
1
2
3
显示:
Authors
John
Luke
注脚
CSDN编辑器支持,某些本地编辑器不支持。
注脚会按照文章的顺序自动排序。
例子:
一个具有注脚的文本。[^1]
[^1]: 注脚的解释
1
2
1
2
显示:
一个具有注脚的文本。1
注释
CSDN编辑器支持,某些本地编辑器不支持。
例子(注释词前后要有空格):
Markdown兼容 HTML 语言。
*[HTML]: 超文本标记语言
1
2
1
2
显示:
Markdown兼容 HTML 语言。
LaTeX公式
CSDN编辑器中支持LaTeX数学公式,详情请见后文的LaTeX公式章节。Typroa软件支持,设置方法详见上文的 Markdown工具 - Typroa - 设置 章节。
Mermaid制图
CSDN编辑器中支持mermaid绘图,如甘特图,UML图等。详情及具体用法请见参考文档。
参考文档:链接 。
需要注意的是:有些本地编辑器不支持mermaid绘图,但如果使用VS Code,则可以通过安装Markdown Preview Enhanced或Markdown Preview Mermaid Support扩展的方式支持,详情请见上文的 Markdown工具 - VS Code - 配合Markdown使用的扩展 章节。
下方是一些图的简单绘制方法。
甘特图
```mermaid
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
section 现有任务
已完成 :done, des1, 2014-01-06,2014-01-08
进行中 :active, des2, 2014-01-09, 3d
计划一 : des3, after des2, 5d
计划二 : des4, after des3, 5d
```
显示:
Mon 06
Mon 13
Mon 20
已完成
进行中
计划一
计划二
现有任务
Adding GANTT diagram functionality to mermaid
UML图
```mermaid
sequenceDiagram
张三 ->> 李四: 你好!李四, 最近怎么样?
李四–>>王五: 你最近怎么样,王五?
李四–x 张三: 我很好,谢谢!
李四-x 王五: 我很好,谢谢!
Note right of 王五: 李四想了很长时间, 文字太长了
不适合放在一行.
李四–>>张三: 打量着王五…
张三->>王五: 很好… 王五, 你怎么样?
```
显示:
张三
李四
王五
你好!李四, 最近怎么样?
你最近怎么样,王五?
我很好,谢谢!
我很好,谢谢!
李四想了很长时间, 文字太长了
不适合放在一行.
打量着王五...
很好... 王五, 你怎么样?
张三
李四
王五
FLowchart流程图
```mermaid
flowchat
st=>start: 开始
e=>end: 结束
op=>operation: 我的操作
cond=>condition: 确认?
st->op->cond
cond(yes)->e
cond(no)->op
```
显示:
开始
我的操作
确认?
结束
yes
no
导出与导入
导出
用户可以在CSDN文章中任意编辑。完成了一篇文章的写作后, 可以在上方工具栏找到 导出按钮 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果用户想加载一篇自己写过的.md文件或者.html文件,在上方工具栏可以选择导入按钮进行对应扩展名的文件导入,并继续创作。
字符实体
前言
与HTML字符实体相同,详情可参照HTML字符实体 。
空格
不换行空格,全称是 No-Break Space,它是最常见和我们使用最多的空格,大多数的人可能只接触了 ,它是按下space键产生的空格。在HTML中,如果你用空格键产生此空格,空格是不会累加的(只算1个)。要使用html实体表示才可累加,该空格占据宽度受字体影响明显而强烈。
半角空格,全称是 En Space,en是字体排印学的计量单位,为em宽度的一半。根据定义,它等同于字体度的一半(如16px字体中就是8px)。名义上是小写字母n的宽度。此空格传承空格家族一贯的特性:透明的,此空格有个相当稳健的特性,就是其占据的宽度正好是1/2个中文宽度,而且基本上不受字体影响。
全角空格,全称是 Em Space,em是字体排印学的计量单位,相当于当前指定的点数。例如,1 em在16px的字体中就是16px。此空格也传承空格家族一贯的特性:透明的,此空格也有个相当稳健的特性,就是其占据的宽度正好是1个中文宽度,而且基本上不受字体影响。
其他
显示结果 描述 实体名称 实体编号
空格
< 小于号 < <
|大于号 |> |>
≦ |小于等于 |≤
≧ |大于等于 |≥
& |和号 |& |&
" |引号 |" |"
’ |撇号 |' (IE不支持) |'
¢ |分 |¢ |¢
£ |镑 |£ |£
¥ |日圆 |¥ |¥
€ |欧元 |&euro |€
§ |小节 |§ |§
© |版权 |© |©
® |注册商标 |® |®
™ |商标 |™ |™
× |乘号 |× |×
÷ |除号 |÷ |÷
转义字符
写法:\+字符
用途:当某些特殊字符与Markdown语法冲突时,使用转义字符可以使字符强制显示,字符实体也可用转义字符显示。
示例:
\>
显示:>
\=\=
显示:==
\>
显示:>
等等
注意:使用字符实体也可以达到一样的效果,但不常用的或记不住的字符实体建议使用转义字符。
首行缩进
缩进2个汉字大小:
使用2个 (推荐)
使用4个
使用8个
空行
连续输入2个回车,即可打出一个空行。
输入HTML表签<br>,即可打出一个换行。
字体
普通文本:
*强调文本* _强调文本_
**加粗文本** __加粗文本__
==标记文本==
~~删除文本~~
> 引用文本
1
2
3
4
5
1
2
3
4
5
显示:
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
注意:强调文本即斜体文本。
组合文本:
加粗加斜:使用***或___
例子:***加粗加斜***
显示:加粗加斜
上下标
CSDN编辑器
此方法可能不适用某些本地编辑器,本地编辑器可以使用HTML方法或LaTeX公式方法。
上标:^文本^
下标:~文本~
例子:
H~2~O
2^10^
显示:
H2O
210
HTML方法
此方法比较同用,适用于各种Markdown编辑器,因为Markdown支持HTML。显示效果与CSDN编辑器相同。
上标:<sup>文本</sup>
下标:<sub>文本</sub>
例子:
H<sub>2</sub>O
2<sup>10</sup>
显示:
H2O
210
LaTeX公式方法
详情请见下文的 附录 LaTeX公式细节 - 上下标 章节。以下为简单的例子。
例子:
$x^z_{y+1}$
显示:
x y + 1 z x^z_{y+1}x
y+1
z
引用可嵌套
例子:
>这是引用的内容
>>这是引用的内容
>>>>>>>>>>这是引用的内容
1
2
3
1
2
3
显示:
这是引用的内容
这是引用的内容
这是引用的内容
目录
Markdown基本语法并没有生成目录的功能,但很多平台或软件都支持生成目录,比如:CSDN博客平台、Typroa软件、等等。使用方法如下,输入下方命令即可在相应位置插入目录,该目录为Markdown文档内的标题组成的目录:
CSDN博客
@[TOC](目录名称) 或 @[toc](目录名称) 。
Typroa
[TOC] 或 [toc] 。
其他
同Typroa。
导出分页
在Markdown导出为PDF时,若想要设置分页,在Markdown文件想分页的位置输入如下HTML代码即可,再次导出即可显示分页效果。该语句已在Typroa软件中实验成功。
<div style="page-break-after: always;"></div>
或
<div STYLE="page-break-after: always;"></div>
1
2
3
1
2
3
链接
格式:[链接文本](链接地址 '链接标题')
说明:链接文本为显示的文字,链接地址为链接的网址,链接标题可以不写,是鼠标悬停在链接处显示的标题。
例子:
[Link](https://mp.csdn.net)
显示:
Link
列表
有序列表
示例:
1. 项目1
2. 项目2
3. 项目3
1
2
3
1
2
3
显示:
项目1
项目2
项目3
无序列表
示例:
- 项目
- 项目
- 项目
1
2
3
1
2
3
显示:
项目
项目
项目
待办列表
示例:
- [ ] 计划任务
- [x] 完成任务
1
2
1
2
显示:
计划任务
完成任务
多级列表
每写下一级有序列表或无须列表时,多缩进1个Tab(推荐)或 4 个空格。
有序多级列表示例:
1. 标题1
1. 标题1.1
1. 标题1.1.1
2. 标题1.1.2
2. 标题1.2
3. 标题1.3
2. 标题2
1
2
3
4
5
6
7
1
2
3
4
5
6
7
显示:
标题1
标题1.1
标题1.1.1
标题1.1.2
标题1.2
标题1.3
标题2
无序多级列表示例:
- 项目
- 项目
- 项目
1
2
3
1
2
3
显示:
项目
项目
项目
自定义列表
注意:CSDN编辑器支持,某些本地编辑器不支持。
例子(最前面要有空行):
Authors
: John
: Luke
1
2
3
1
2
3
显示:
Authors
John
Luke
图片
Markdown图片
插入图片格式:
在这里插入图片描述
注意: 图片替换文本是图片未显示时替换的文本,图片标题是鼠标悬停在图片上显示的文本,图片标题可不写,图片标题的引号用单引号和双引号都可以。图片地址可以是网络网址(https://xxx),也可以是本地相对路径(推荐,如./images/pic1.jpg)或绝对路径。
例子:
![Alt](https://img-blog.csdnimg.cn/20210531154235861.png 'title')
显示:
Alt
CSDN图片
CSDN平台针对Markdown的图片语法做了特殊处理,支持调整图片的大小和对齐方式,使用方法如下:
带尺寸的图片:
![Alt](https://img-blog.csdnimg.cn/20210531154235861.png# =30x30)
显示:
Alt
居中的图片:
![Alt](https://img-blog.csdnimg.cn/20210531154235861.png#pic_center)
补充:图片居左为#pic_left,图片居右为#pic_right 。
显示:
Alt
居中并且带尺寸的图片:
![Alt](https://img-blog.csdnimg.cn/20210531154235861.png#pic_center =30x30)
显示:
Alt
为了让用户更加便捷,CSDN博客增加了图片拖拽功能。
HTML图片
即使不在CSDN平台,Markdown编辑器也可以实现调整图片大小和对齐方式的功能,因为Markdown支持HTML,使用HTML语言即可,使用方法如下:
居中图片
代码:
<div align=[对齐方式]> <!--对齐方式可以为center,left,right-->
<img src="图片地址" alt="替换文字" width="宽度" height="高度">
</div>
1
2
3
1
2
3
示例1:居中的图片
<div align=center>
<img src="https://img-blog.csdnimg.cn/2021053115541388.png">
</div>
1
2
3
1
2
3
显示:
示例2:居中且带尺寸的图片
<div align=center>
<img src="https://img-blog.csdnimg.cn/2021053115541388.png" width="50%">
</div>
1
2
3
1
2
3
显示:
图片居中标题
无论以何种方式插入图片,都有在图片下方输入图片标题的需求,使用HTML语法即可为图片添加居中标题,使用方法如下:
在图片下方添加如下HTML代码即可:
<center>图片标题</center>
1
1
显示:
图片标题
表格
如果表格贴近行首,则可以使用简便方式制作表格
例子:
列1 | 列2
--- | ---
值1 |值2
值3 |值4
1
2
3
4
1
2
3
4
显示:
列1 列2
值1 值2
值3 值4
若表格前有Tab缩进,则左侧的 | 需补全,否则会出现第一列不显示的状况。
例子:
| 列1 | 列2
| --- | ---
| 值1 |值2
| 值3 |值4
1
2
3
4
1
2
3
4
显示:
列1 列2
值1 值2
值3 值4
完整的表格格式。
例子:
| 列1 | 列2 | 列3 |
| :--- | :---: | ---: |
| 文本居左 | 文本居中 | 文本居右 |
1
2
3
1
2
3
显示:
列1 列2 列3
文本居左 文本居中 文本居右
注意:最左侧(第一个) | 右端最好有1或2个空格,否则可能会出现未知错误(如缺失字符,对齐失效等)。
分割线
三个或者三个以上的 - 或者 * 都可以,效果是一样的。
注意分割线前要有空行。
例子:
(空行)
---
----
***
*****
1
2
3
4
5
1
2
3
4
5
显示:
代码块
单行代码块
代码只有一行或在文本中插入时可以使用,也可以叫行中代码块,格式为:`代码` 。
例子:
`print('Hello World!)`
显示:
print('Hello World!)
多行代码块
多行代码块可以插入多行代码,且可以标记编程语言的类型,如python,可以简写成py,JavaScript可以简写成js。
格式:
```编程语言类型
代码片段
代码片段
```
例子:
```py
for i in(1,11,1):
print(‘Hello World!’,end=‘\n’)
```
显示:
for i in(1,11,1):
print('Hello World!',end='\n')
1
2
1
2
技巧
代码块前面可以使用Tab缩进,显示的代码块前端也会有缩进。
例子:
print('前面有缩进。')
1
1
在CSDN博客设置页面,可以选择一款自己喜欢的代码片高亮样式。
LaTeX数学公式
介绍
CSDN支持LaTeX公式,但有些本地编辑器可能不支持LaTeX公式,Typroa可以更改设置支持,VS Code可以通过安装扩展的方式支持,详情请见上文的 Markdown工具 章节。
LaTeX数学公式的各种细节请参见我的另一篇博客:LaTeX数学公式-详细教程 。
官方文档:
传送门:官方文档
网址:https://math.meta.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference
中文教程:
传送门:中文教程
网址:https://www.jianshu.com/p/25f0139637b7
技巧:使用在线LaTeX公式编辑器,来生成LaTeX公式代码,然后复制到Markdown编辑器中,并在两边加上$或$$即可。
在线LaTeX公式编辑器网址:https://private.codecogs.com/latex/eqneditor.php
插入公式
左对齐公式(行中公式):$数学公式$
居中公式(独立公式):$$数学公式$$
注意:使用$行中公式时,数学公式与$连接处不要有空格,否则公式不会显示;使用$$居中公式时,数学公式与$$连接处可以有空格。即$ 数学公式 $ 不显示公式。
注释:%为单行注释。
细节:细节请参见我的另一篇博客:LaTeX数学公式-详细教程 。
注意事项
使用$,即行中公式时,数学公式与$连接处不要有空格,否则公式不会显示。
使用$$,即居中公式时,数学公式与$$连接处可以有空格。即$ 数学公式 $ 不显示公式。
使用$$时,上方要空一行。
=不要单独打一行,否则可能会出错。
+ - * / = ( ) | , . '等符号直接在$或$$之间输入即可识别。
② 关于中断嵌套的问题
关于中断嵌套:在linux内核里,如果驱动在申请注册中断的时候没有特别的指定,do_irq在做中断响应的时候,是开启中断的,如果在驱动的中断处理函数正在执行的过程中,出现同一设备的中断或者不同设备的中断,这时候新的中断会被立即处理,还是被pending,等当前中断处理完成后,再做处理。在2.4和2.6内核里,关于这一块是否有什么不同。 一般申请中断的时候都允许开中断,即不使用SA_INTERRUPT标志。如果允许共享则加上 SA_SHIRQ,如果可以为内核熵池提供熵值(譬如你写的驱动是ide之类的驱动),则再加上 SA_SAMPLE_RANDOM标志。这是普通的中断请求过程。对于这种一般情况,只要发生中断,就可以抢占内核,即使内核正在执行其他中断函数。这里有两点说明:一是因为linux不支持 中断优先级,因此任何中断都可以抢占其他中断,但是同种类型的中断(即定义使用同一个 中断线的中断)不会发生抢占,他们会在执行本类型中断的时候依次被调用执行。二是所谓 只要发生中断,就可以抢占内核这句是有一定限制的,因为当中断发生的时候系统由中断门 进入时自动关中断(对于x86平台就是将eflags寄存器的if位置为0),只有当中断函数被执行 (handle_IRQ_event)的过程中开中断之后才能有抢占。 对于同种类型的中断,由于其使乱竖用同样的idt表项,通过其状态标志(IRQ_PENDING和 IRQ_INPROGRESS)可以空毁防止同种类型的中断函数执行(注意:是防止handle_IRQ_event被重入, 而不是防止do_IRQ函数被重入),对于不同的中断,则可以自由的嵌套。因此,所谓中断嵌套, 对于不同的中断是可以自由嵌套的,而对于同种类型的中断,是不可以嵌套执行的。以下简单解释一下如何利斗陪备用状态标志来防止同种类型中断的重入:当某种类型的中断第一次发生时,首先其idt表项的状态位上被赋予IRQ_PENDING标志,表示有待处理。 然后将中断处理函数action置为null,然后由于其状态没有IRQ_INPROGRESS标志(第一次),故将其状态置上IRQ_INPROGRESS并去处IRQ_PENDING标志,同时将action赋予相应的中断处理函数指针(这里是一个重点,linux很巧妙的用法,随后说明)。这样,后面就可以顺利执行handle_IRQ_event进行中断处理,当在handle_IRQ_event中开中断后,如果有同种类型的中断发生,则再次进入do_IRQ函数,然后其状态位上加上IRQ_PENDING标志,但是由于前一次中断处理中加上的IRQ_INPROGRESS没有被清除,因此这里无法清除IRQ_PENDING标志,因此action还是为null,这样就无法再次执行handle_IRQ_event函数。从而退出本次中断处理,返回上一次的中断处理函数中,即继续执行handle_IRQ_event函数。当handle_IRQ_event返回时检查IRQ_PENDING标志,发现存在这个标志,说明handle_IRQ_event执行过程中被中断过,存在未处理的同类中断,因此再次循环执行handle_IRQ_event函数。直到不存在IRQ_PENDING标志为止。2.4和2.6的差别,就我来看,主要是在2.6中一进入do_IRQ,多了一个关闭内核抢占的动作,同时在处理中多了一种对IRQ_PER_CPU类型的中断的处理,其他没有什么太大的改变。这类IRQ_PER_CPU的中断主要用在smp环境下将中断绑定在某一个指定的cpu上。例如arch/ppc/syslib/open_pic.c中的openpic_init中初始化ipi中断的时候。 其实简单的说,中断可以嵌套,但是同种类型的中断是不可以嵌套的,因为在IRQ上发生中断,在中断响应的过程中,这个IRQ是屏蔽的,也就是这个IRQ的中断是不能被发现的。 同时在内核的临界区内,中断是被禁止的 关于do_IRQ可能会丢失中断请求:do_IRQ函数是通过在执行完handle_IRQ_event函数之后判断status是否被设置了IRQ_PENDING标志来判断是否还有没有被处理的同一通道的中断请求。 但是这种方法只能判断是否有,而不能知道有多少个未处理的统一通道中断请求。也就是说,假如在第一个中断请求执行handle_IRQ_event函数的过程中来了同一通道的两个或更多中断请求,而这些中断不会再来,那么仅仅通过判断status是否设置了IRQ_PENDING标志不知道到底有多少个未处理的中断,handle_IRQ_event只会被再执行一次。这算不算是个bug呢? 不算,只要知道有中断没有处理就OK了,知道1个和知道N个,本质上都是一样的。作为外设,应当能够处理自己中断未被处理的情况。不可能丢失的,在每一个中断描述符的结构体内,都有一个链表,链表中存放着服务例程序关于中断中使用的几个重要概念和关系: 一、基本概念 1. 产生的位置 发生的时刻 时序 中断 CPU外部 随机 异步 异常 CPU正在执行的程序 一条指令终止执行后 同步 2.由中断或异常执行的代码不是一个进程,而是一个内核控制路径,代表中断发生时正在运行的进程的执行 中断处理程序与正在运行的程序无关 引起异常处理程序的进程正是异常处理程序运行时的当前进程 二、特点 (2)能以嵌套的方式执行,但是同种类型的中断不可以嵌套 (3)尽可能地限制临界区,因为在临界区中,中断被禁止 2.大部分异常发生在用户态,缺页异常是唯一发生于内核态能触发的异常 缺页异常意味着进程切换,因此中断处理程序从不执行可以导致缺页的操作 3.中断处理程序运行于内核态 中断发生于用户态时,要把进程的用户空间堆栈切换到进程的系统空间堆栈,刚切换时,内核堆栈是空的 中断发生于内核态时, 不需要堆栈空间的切换 三、分类 1.中断的分类:可屏蔽中断、不可屏蔽中断 2.异常的分类: 分类 解决异常的方法 举例 故障 那条指令会被重新执行 缺页异常处理程序 陷阱 会从下一条指令开始执行 调试程序
③ 内核不停切换
内核态与用户态是操作系统的两种运行级别,intel cpu提供Ring0-Ring3三种级别的运行模式。Ring0级别最高,Ring3最低。其中特权级0(Ring0)是留给操作系统代码,设备驱动程序代码使用的,它们工作于系统核心态;而特权极3(Ring3)则给普通的用户程序使用,它们工作在用户态。运行于处理器核心态的代码不受任何的限制,可以自由地访问任何有效地址,进行直接端口访问。而运行于用户态的代码则要受到处理器的诸多检查,它们只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址,且只能对任务状态段(TSS)中I/O许可位图(I/O Permission Bitmap)中规定的可访问端口进行直接访问(此时处理器状态和控制标志寄存器EFLAGS中的IOPL通常为0,指明当前可以进行直接I/O的最低特权级别是Ring0)。以上的讨论只限于保护模式操作系统,象DOS这种模式操作系统则没有这些概念,其中的所有代码都可被看作运行在核心态。
当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级) 内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执冲旁行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。
在内核态下CPU可执行任何指令,在用户态下CPU只能执行非特权指令。当CPU处于内核态,可以随意进入用户态;而当CPU处于用户态时,用户从用户态切换到内核态只有在系统调用和中断两种情况下发生,一般程序一开始都是运行于用户态,当程序需要使用系统资源时,就必须通过调用软中断进入内核态。
Linux使用了Ring3级别运行用户态,Ring0作为内核态,没有使用Ring1和Ring2。Ring3状态不能访问Ring0的地址空间,包括代码和数据。Linux进程的4GB地址空间,3G-4G部分大家是共享的,是内核态的地址空间,这里存放在整个内核的代码和所有的内核模块,以及内核所维护的数据。用户运行一个程序,该程序所创建的进程开始是运行在用户态的,如果要执行文件操作,网络数据发送等操作,必须通过 write,send等系统调用,这些系统调用会调用内核中的代码来完成操作,这时,必须切换到Ring0,然后进入3GB-4GB中的内核地址空间去执行这些代码完成操作,完成后,切换回Ring3,回到用户态。这样,用户态的程序就不能随意操作内核地址空间,具有一定的安全保护作用。
处理器模式从Ring3向Ring0的切换发生在控制权转移时,有以下两种情况:访问调用门的长转移指令CALL,访问中断门或陷阱门的INT指令。具体的转移细节由于涉及复杂的保护检查和堆栈切换,不再赘述,请参阅相关资料。现代的操作系统通常使用中断门来提供系统服务,通过执行一条陷入指令来完成模式切换,在INTEL X86上这条指令是INT,如在森尘WIN9X下是INT30(保护模式回调),在LINUX下是INT80,在WINNT/2000下是INT2E。用户模式的服务程序(如系统DLL)通过执行一个INTXX来请求系统服务,然后处理器模式将切换到核心态,工作于核心态的相应的系统代码将服务于此次请求并将结果传给用户程序。
一,中断处理过程
硬件中断:来自时钟,外设
可编程中断:programmed interrupt,执行引起软件中断的指散春橡令。
例外中断:如页面错。
都由系统负责处理。当发生一个中断时,如果CPU正在比该中断级低的处理机运行级上运行,它就在解码下条指令之前,接受该中断,并提高处理机运行级。内核处理中断的操作顺序如下:
1,对于正在进行的进程,保存其当前寄存器上下文,并创建压入一个新的上下文层。
2,确定中断源,识别中断类型。如是时钟或磁盘的。
3,查找中断向量。当系统接受一个中断时,它从机器中得到一个数,系统把这个作为查表的偏移量。这个表通常成为中断向量(interrupt vector)。中断向量的内容包括各种中断源的中断处理程序的地址,以及中断处理程序取得参数的方式。
4,内核调用中断处理程序。
5,中断处理程序执行那个返回,恢复(弹出)前一上下文层。
二,软中断
软中断通知进程发生了异步事件。
系统有个进程表,每个进程在进程表中有有个进程表项,每个进程表项有个软中断信号字段,纪录发向一个进程的所有未处理的软中断信号。
当一个进程即将从核心态返回到用户态时,或它要进入或离开一个适当的低调度优先级时,内核要检查它是否收到了一个软中断信号。
内核仅当一个进程从核心态返回到用户态时才处理软中断信号。
三,系统调用
我们在C程序中调用系统调用好像是个一般的函数调用,当实际上调用系统调用会引起用户态到核心态的状态变化,这是怎么做到的呢?
原来,C编译程序采用一个预定义的函数库(C之程序库),其中的函数具有系统调用的名字,从而解决了在用户程序中请求系统调用的问题。这些库函数一般都执行一条指令,该指令将进程的运行方式变为核心态,然后,使内核开始为系统调用执行代码。我们称这个指令为操作系统陷入(operating system trap)。
系统调用的接口是一个中断处理程序的特例。
在处理操作系统陷入时,
1,内核根据系统调用号查系统调用入口表,找到相应的内核子程序的地址。
2,内核还要确定该系统调用所要求的参数个数。
3,从用户地址空间拷贝参数到U区(Unix V)。
4,保存当前上下文,执行系统调用代码。
核心态:当CPU正在运行内核代码时(内核代码是共享的)。
用户态:当CPU正在运行用户代码时。
用户模式:不可以访问内核空间(>=0x80000000)
内核模式:可以访问任何有效虚拟地址,包括内核空间。一个线程可以访问其他任何线程地址空间。
④ 麻将中断门什么意思是条,饼,万,一样都不能少,还是必须有其中两种才能胡牌。缺一种才能赢求详解
断门应该是条,饼,万中至少要缺一门,才能胡,至于糊牌之前是不是必须报听不同的地方应该不同,河北尺信牌的话不需要必须报听,类似的玩法如打八张,活八张是条,饼,万,风(字牌)有一门至少有八张才能胡,死八张是其中必须有一门有八张,不能多也不能少,才能胡,麻将不同的地方的习俗有很大不同,不知道你打的是哪扒缺里的牌,,,具体的情况要根据地方习陵此轮俗才能确定,,
⑤ 进程间切换和线程间切换分别做些什么工作啊
进程:
在中断描述符表(IDT)中,除中断门、陷阱门和调用门外,还有一种“任务们”。任务门中包含有TSS段的选择符。当CPU因中断而穿过一个任务门时,就会将任务门中的段选择符裂游自动装入TR寄存器,使指向新的TSS,并完成任务切换。CPU可以通过JMP或CALL指令实现任务切换肆早销,当跳转或调用的目标段(代码段)实际上指向GDT表中的一个TSS描述符项时,就会引起一次任务切换.
线程:
1.时间片:时钟中断处理例程从PCR中取得当前线程对象睁银指针并更新线程时间,如果超出了时间片,则将当前线程从放入ready列表中,然后从standby列表中取出最高优先级的线程,然后保存当前线程上下文数据,并转到新的线程上下文.
2.主动等待:线程调用等待函数,则将当前线程放到wait列表中,然后从standby列表中取一个线程,切换上下文,当主动等待的事件完成时,线程被调度到ready列表中等待再次被调度运行.
3.抢先:时钟中断发现standby列表中有比当前线程更高的线程,则挂起当前线程,切换线程上下文,运行最需要运行的线程.
所以,线程间切换就是"线程挂起自己,让出CPU"
⑥ C++代码 有办法封A变速齿轮么
正常 我机器以前也遇到这方面问题
在系统时间上与WINDOS进行同步连接
变速齿轮的原理是把一个程序在处理上先进行这个软件上的过滤
下面是其中一段源代码
// File name : SetClock.cpp
// Function1 : SetClock9x(int)
// Function2 : SetClockNT(int)
// Chu Rui 2001.3.1
#include "stdafx.h"
#include "ntport.h"
#define FREE_INT_NO 5
void Ring0()
{ //在Windows9x下进入ring0后进行的操作
__asm
{
cli
mov al,34h
out 43h,al //写入8253控制寄存器,设置写0号定时轿键仿器
mov ax,bx
out 40h,al //写定时值低位
mov al,ah
out 40h,al //写定时值高位
sti
iretd;
}
}
void SetClockNT(int freq)
{ //NT下的操作
//这里使用了NT Port库
Outport(0x43,0x34); //写入8253控制寄存器,设置写0号定时器
Outport(0x40,freq&0xff); //写定时值低亮并位
Outport(0x40,(freq>>8)&0xff); //写定时值高位
}
void SetClock9x(int freq)
{
union Function_Pointer
{
void (*pointer)();
char bytes[sizeof(void *)];
}OldIntAddress,NewIntAddress;
int IDTAddress; //IDT表基地址
int IDTItemAddress; //要修改的中断门所在地址
char *Pointer; //要修改的中断门所在地址,指针形式
__asm
{
push eax
sidt [esp-2]
pop eax
mov IDTAddress,eax //得到IDT表基地闭纤址
}
IDTItemAddress=FREE_INT_NO*8+IDTAddress;
Pointer=(char *)IDTItemAddress;
NewIntAddress.pointer=Ring0;
OldIntAddress.bytes[0]=Pointer[0];
OldIntAddress.bytes[1]=Pointer[1];
OldIntAddress.bytes[2]=Pointer[6];
OldIntAddress.bytes[3]=Pointer[7]; //保存旧的中断门
Pointer[0]=NewIntAddress.bytes[0];
Pointer[1]=NewIntAddress.bytes[1];
Pointer[6]=NewIntAddress.bytes[2];
Pointer[7]=NewIntAddress.bytes[3]; //设置新的中断门
__asm
{
mov ebx,freq
int FREE_INT_NO //产生中断,进入ring0
}
Pointer[0]=OldIntAddress.bytes[0];
Pointer[1]=OldIntAddress.bytes[1];
Pointer[6]=OldIntAddress.bytes[2];
Pointer[7]=OldIntAddress.bytes[3]; //恢复旧的中断门
}
⑦ 系统中断的中断处理
中断处理一般分为中断响应和中断处理两个步骤。中断响应由硬件实施,中断处理弊或主要由软件实施。
(1)中断响应
对中断请求的整个处理过程是由硬件和软件结合起来而形成的一套中断机构实施的。发生中断时,CPU暂停执行当前的程序,而转去处理中断。这个由硬件对中断请求作出反应的过程,称为中断响应。一般说来,中断响应顺序执行下述三步动作:
◆中止当前程序的执行;
◆保存原程序的断点信息(主要是程序计数器PC和程序状态寄存器PS的内容);
◆从中断控制器取出中断向量,转到相应的处理程序。
通常CPU在执行完一条指令后,立即检查有无中断请求,如果有,则立即做出响应。
当发生中断时,系统作出响应,不管它们是来自硬件(如来自时钟或者外部设备)、程序性中断(执行指令导致“软件中断”—Software Interrupts),或者来自意外事件(如访问页面不在内存)。
如果当前CPU的执行优先级低于中断的优先级,那么它就中止对当前程序下条指令的执行,接受该中断,并提升处理机的执行级别(一般与中断优先级相同),以便在CPU处理当前中断时,能屏蔽其它同级的或低级的中断,然后保存断点现场信息,通过取得的中断向量转到相应的中断处理程序的入口。
(2)中断处理
CPU从中断控制器取得中断向量,然后根据具体的中断向量从中断向量表IDT中找到相应的表项,该表项应是一个中断门。于是,CPU就根据中断门的设置而到达了该通道的总服务程序的入口。
核心对中断处理的顺序主要由以下动作完成:
◆保存正在运行进程的各寄存器的内容,把它们放入核心栈的新帧面中。
◆确定“中断源”或核查中断发生,识别中断的类型(如时钟中断或盘中断)和中断的设备号(如哪个磁盘引起的中断)。系统接到中断后,就从机器那里得拍笑到一个中断号,它是检索中断向量表的位移。中断向量因机器而异,但通常都包括相应中断处理程序入口地址和中断处理时处理机的状态字。
◆核心调用中断处理程序,对中断进行处理。
◆中断处理完成并返回。中断处理程序执行完以后,核心便执行与机器相关的特定指令序列,恢复中断时寄存器内容租贺伍和执行核心栈退栈,进程回到用户态。如果设置了重调度标志,则在本进程返回到用户态时做进程调度。
⑧ VC++ MFC如何获取CPU ID及硬盘的序列号
// “获得Intel CPU ID”按钮消息处理函数
void CIntelCPUIDDlg::OnBtnCPUID()
{
unsigned long s1,s2;
unsigned char vendor_id[]="------------";//CPU提供商ID
CString str1,str2,str3;
// 以下为获得CPU ID的汇编语言指令
_asm // 得到CPU提供梁团缺商信息
{
xor eax,eax // 将eax清0
cpuid /橡辩/ 获取CPUID的指令
mov dword ptr vendor_id,ebx
mov dword ptr vendor_id[+4],edx
mov dword ptr vendor_id[+8],ecx
}
str1.Format("%s",vendor_id);
_asm // 得到CPU ID的高32位
{
mov eax,01h
xor edx,edx
cpuid
mov s2,eax
}
str2.Format("%08X-",s2);
_asm // 得到CPU ID的低64位
{
mov eax,03h
xor ecx,ecx
xor edx,edx
cpuid
mov s1,edx
mov s2,ecx
}
str3.Format("%08X-%08X\n",s1,s2);
str2=str2+str3;
m_editVendor.SetWindowText(str1);
m_editCPUID.SetWindowText(str2);
}
// GetHDSerial.cpp: implementation of the CGetHDSerial class.
//
//////////////////////////////////////////////////////或睁////////////////
#include "stdafx.h"
#include "GetHDSerial.h"
char m_buffer[256];
WORD m_serial[256];
DWORD m_OldInterruptAddress;
DWORDLONG m_IDTR;
// 等待硬盘空闲
static unsigned int WaitHardDiskIdle()
{
BYTE byTemp;
Waiting:
_asm
{
mov dx, 0x1f7
in al, dx
cmp al, 0x80
jb Endwaiting
jmp Waiting
}
Endwaiting:
_asm
{
mov byTemp, al
}
return byTemp;
}
//中断服务程序
void _declspec( naked )InterruptProcess(void)
{
int byTemp;
int i;
WORD temp;
//保存寄存器值
_asm
{
push eax
push ebx
push ecx
push edx
push esi
}
WaitHardDiskIdle();//等待硬盘空闲状态
_asm
{
mov dx, 0x1f6
mov al, 0xa0
out dx, al
}
byTemp = WaitHardDiskIdle(); //若直接在Ring3级执行等待命令,会进入死循环
if ((byTemp&0x50)!=0x50)
{
_asm // 恢复中断现场并退出中断服务程序
{
pop esi
pop edx
pop ecx
pop ebx
pop eax
iretd
}
}
_asm
{
mov dx, 0x1f6 //命令端口1f6,选择驱动器0
mov al, 0xa0
out dx, al
inc dx
mov al, 0xec
out dx, al //发送读驱动器参数命令
}
byTemp = WaitHardDiskIdle();
if ((byTemp&0x58)!=0x58)
{
_asm // 恢复中断现场并退出中断服务程序
{
pop esi
pop edx
pop ecx
pop ebx
pop eax
iretd
}
}
//读取硬盘控制器的全部信息
for (i=0;i<256;i++)
{
_asm
{
mov dx, 0x1f0
in ax, dx
mov temp, ax
}
m_serial[i] = temp;
}
_asm
{
pop esi
pop edx
pop ecx
pop ebx
pop eax
iretd
}
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CGetHDSerial::CGetHDSerial()
{
}
CGetHDSerial::~CGetHDSerial()
{
}
// 读取硬盘序列号函数
char* CGetHDSerial::GetHDSerial()
{
m_buffer[0]='\n';
// 得到当前操作系统版本
OSVERSIONINFO OSVersionInfo;
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx( &OSVersionInfo);
if (OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
{
// Windows 9x/ME下读取硬盘序列号
WORD m_wWin9xHDSerial[256];
Win9xReadHDSerial(m_wWin9xHDSerial);
strcpy (m_buffer, WORDToChar (m_wWin9xHDSerial, 10, 19));
}
else
{
// Windows NT/2000/XP下读取硬盘序列号
DWORD m_wWinNTHDSerial[256];
// 判断是否有SCSI硬盘
if ( ! WinNTReadIDEHDSerial(m_wWinNTHDSerial))
WinNTReadSCSIHDSerial(m_wWinNTHDSerial);
strcpy (m_buffer, DWORDToChar (m_wWinNTHDSerial, 10, 19));
}
return m_buffer;
}
// Windows9X/ME系统下读取硬盘序列号
void _stdcall CGetHDSerial::Win9xReadHDSerial(WORD * buffer)
{
int i;
for(i=0;i<256;i++)
buffer[i]=0;
_asm
{
push eax
//获取修改的中断的中断描述符(中断门)地址
sidt m_IDTR
mov eax,dword ptr [m_IDTR+02h]
add eax,3*08h+04h
cli
//保存原先的中断入口地址
push ecx
mov ecx,dword ptr [eax]
mov cx,word ptr [eax-04h]
mov dword ptr m_OldInterruptAddress,ecx
pop ecx
//设置修改的中断入口地址为新的中断处理程序入口地址
push ebx
lea ebx,InterruptProcess
mov word ptr [eax-04h],bx
shr ebx,10h
mov word ptr [eax+02h],bx
pop ebx
//执行中断,转到Ring 0(类似CIH病毒原理)
int 3h
//恢复原先的中断入口地址
push ecx
mov ecx,dword ptr m_OldInterruptAddress
mov word ptr [eax-04h],cx
shr ecx,10h
mov word ptr [eax+02h],cx
pop ecx
sti
pop eax
}
for(i=0;i<256;i++)
buffer[i]=m_serial[i];
}
// Windows 9x/ME系统下,将字类型(WORD)的硬盘信息转换为字符类型(char)
char * CGetHDSerial::WORDToChar (WORD diskdata [256], int firstIndex, int lastIndex)
{
static char string [1024];
int index = 0;
int position = 0;
// 按照高字节在前,低字节在后的顺序将字数组diskdata 中内容存入到字符串string中
for (index = firstIndex; index <= lastIndex; index++)
{
// 存入字中的高字节
string [position] = (char) (diskdata [index] / 256);
position++;
// 存入字中的低字节
string [position] = (char) (diskdata [index] % 256);
position++;
}
// 添加字符串结束标志
string [position] = '\0';
// 删除字符串中空格
for (index = position - 1; index > 0 && ' ' == string [index]; index--)
string [index] = '\0';
return string;
}
// Windows NT/2000/XP系统下,将双字类型(DWORD)的硬盘信息转换为字符类型(char)
char* CGetHDSerial::DWORDToChar (DWORD diskdata [256], int firstIndex, int lastIndex)
{
static char string [1024];
int index = 0;
int position = 0;
// 按照高字节在前,低字节在后的顺序将双字中的低字存入到字符串string中
for (index = firstIndex; index <= lastIndex; index++)
{
// 存入低字中的高字节
string [position] = (char) (diskdata [index] / 256);
position++;
// 存入低字中的低字节
string [position] = (char) (diskdata [index] % 256);
position++;
}
// 添加字符串结束标志
string [position] = '\0';
// 删除字符串中空格
for (index = position - 1; index > 0 && ' ' == string [index]; index--)
string [index] = '\0';
return string;
}
// Windows NT/2000/XP下读取IDE硬盘序列号
BOOL CGetHDSerial::WinNTReadIDEHDSerial(DWORD * buffer)
{
BYTE IdOutCmd [sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];
BOOL bFlag = FALSE;
int drive = 0;
char driveName [256];
HANDLE hPhysicalDriveIOCTL = 0;
sprintf (driveName, "\\\\.\\PhysicalDrive%d", drive);
// Windows NT/2000/XP下创建文件需要管理员权限
hPhysicalDriveIOCTL = CreateFile (driveName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
{
GETVERSIONOUTPARAMS VersionParams;
DWORD cbBytesReturned = 0;
// 得到驱动器的IO控制器版本
memset ((void*) &VersionParams, 0, sizeof(VersionParams));
if(DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_VERSION,
NULL, 0, &VersionParams,
sizeof(VersionParams),
&cbBytesReturned, NULL) )
{
if (VersionParams.bIDEDeviceMap > 0)
{
BYTE bIDCmd = 0; // IDE或者ATAPI识别命令
SENDCMDINPARAMS scip;
// 如果驱动器是光驱,采用命令IDE_ATAPI_IDENTIFY, command,
// 否则采用命令IDE_ATA_IDENTIFY读取驱动器信息
bIDCmd = (VersionParams.bIDEDeviceMap >> drive & 0x10)?
IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;
memset (&scip, 0, sizeof(scip));
memset (IdOutCmd, 0, sizeof(IdOutCmd));
// 获取驱动器信息
if (WinNTGetIDEHDInfo (hPhysicalDriveIOCTL,
&scip,
(PSENDCMDOUTPARAMS)&IdOutCmd,
(BYTE) bIDCmd,
(BYTE) drive,
&cbBytesReturned))
{
int m = 0;
USHORT *pIdSector = (USHORT *)
((PSENDCMDOUTPARAMS) IdOutCmd) -> bBuffer;
for (m = 0; m < 256; m++)
buffer[m] = pIdSector [m];
bFlag = TRUE; // 读取硬盘信息成功
}
}
}
CloseHandle (hPhysicalDriveIOCTL); // 关闭句柄
}
return bFlag;
}
// WindowsNT/2000/XP系统下读取SCSI硬盘序列号
BOOL CGetHDSerial::WinNTReadSCSIHDSerial (DWORD * buffer)
{
buffer[0]='\n';
int controller = 0;
HANDLE hScsiDriveIOCTL = 0;
char driveName [256];
sprintf (driveName, "\\\\.\\Scsi%d:", controller);
// Windows NT/2000/XP下任何权限都可以进行
hScsiDriveIOCTL = CreateFile (driveName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE)
{
int drive = 0;
DWORD mmy;
for (drive = 0; drive < 2; drive++)
{
char buffer [sizeof (SRB_IO_CONTROL) + SENDIDLENGTH];
SRB_IO_CONTROL *p = (SRB_IO_CONTROL *) buffer;
SENDCMDINPARAMS *pin =
(SENDCMDINPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
// 准备参数
memset (buffer, 0, sizeof (buffer));
p -> HeaderLength = sizeof (SRB_IO_CONTROL);
p -> Timeout = 10000;
p -> Length = SENDIDLENGTH;
p -> ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
strncpy ((char *) p -> Signature, "SCSIDISK", 8);
pin -> irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
pin -> bDriveNumber = drive;
// 得到SCSI硬盘信息
if (DeviceIoControl (hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,
buffer,
sizeof (SRB_IO_CONTROL) +
sizeof (SENDCMDINPARAMS) - 1,
buffer,
sizeof (SRB_IO_CONTROL) + SENDIDLENGTH,
&mmy, NULL))
{
SENDCMDOUTPARAMS *pOut =
(SENDCMDOUTPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
IDSECTOR *pId = (IDSECTOR *) (pOut -> bBuffer);
if (pId -> sModelNumber [0])
{
int n = 0;
USHORT *pIdSector = (USHORT *) pId;
for (n = 0; n < 256; n++)
buffer[n] =pIdSector [n];
return TRUE; // 读取成功
}
}
}
CloseHandle (hScsiDriveIOCTL); // 关闭句柄
}
return FALSE; // 读取失败
}
// Windows NT/2000/XP下读取IDE设备信息
BOOL CGetHDSerial::WinNTGetIDEHDInfo (HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP,
PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum,
PDWORD lpcbBytesReturned)
{
// 为读取设备信息准备参数
pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;
pSCIP -> irDriveRegs.bFeaturesReg = 0;
pSCIP -> irDriveRegs.bSectorCountReg = 1;
pSCIP -> irDriveRegs.bSectorNumberReg = 1;
pSCIP -> irDriveRegs.bCylLowReg = 0;
pSCIP -> irDriveRegs.bCylHighReg = 0;
// 计算驱动器位置
pSCIP -> irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4);
// 设置读取命令
pSCIP -> irDriveRegs.bCommandReg = bIDCmd;
pSCIP -> bDriveNumber = bDriveNum;
pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;
// 读取驱动器信息
return ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_DRIVE_INFO,
(LPVOID) pSCIP,
sizeof(SENDCMDINPARAMS) - 1,
(LPVOID) pSCOP,
sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,
lpcbBytesReturned, NULL) );
}
⑨ 如何关闭linux smp中断
在多 CPU 的环境中,还有一个中断平衡的问题,比如,网卡中断会教给哪个 CPU 处理,这个参数控制哪些 CPU 可以绑定 IRQ 中断。其中的 {number} 是对应设备的中断编号,可以用下面的命令找出:
cat /proc/interrupt
比如,一般 eth0 的 IRQ 编号是 16,所以控制 eth0 中断绑定的 /proc 文件名是 /proc/irq/16/smp_affinity。上面这个命令还可以看到某些中断对应的CPU处理的次数,缺省的时候肯定是不平衡的。
设置其值的方法很简单,smp_affinity 自身是一个位掩码(bitmask),特定的位对应特定的 CPU,这样,01 就意味着只有第一个 CPU 可以处理对应的中断,而 0f(0x1111)意味着四个 CPU 都会参与中断处理。
几乎所有外设都有这个参数设置,可以关注一下。
这个数值的推荐设置,其实在很大程度上,让专门的CPU处理专门的中断是效率最高的,比如,给磁盘IO一个CPU,给网卡一个CPU,这样是比较合理的。
现在的服务器一般都是多核了,但是中断很多时候都是只用一个核,如果有些中断要求比较高,可以把它独立分配给一个cpu使用。
⑩ windows 系统调用 是中断门 还是陷阱门
windows
系统调用是陷阱门,中断门用于外设,也就是CPU外部岁携,属于异步中断。异常包括故障、陷阱、中止。系统调用使用乎旅伏陷阱门并且区别于CPU内部常用异常的特点在于DPL=3。一般或者说多数DPL=0。
再看看别人怎镇正么说的。