linux整体注释
linux整体注释
![linux整体注释](https://img.taocdn.com/s3/m/8e270ecebdeb19e8b8f67c1cfad6195f302be868.png)
linux整体注释
在Linux中,注释是用来对代码进行解释和说明的一种方式。
注释通常是以特殊的符号或关键字开始,以标识其为注释内容,而不是实际的代码。
注释不会被编译或执行,它们只是为了帮助开发人员理解代码的意图和功能。
在Linux中,常见的注释格式包括单行注释和多行注释。
单行注释使用特定的符号(如“#”)在代码行的开头进行标记,后面的内容将被视为注释。
例如:
```bash
# 这是一个单行注释
```
多行注释使用特定的符号对注释内容进行标记,通常是在一对符号之间的所有内容都被视为注释。
例如,在Shell脚本中可以使用“:”符号或“<<EOF”符号来标记多行注释:
```bash
: '
这是一个多行注释
可以包含多行内容
'
```
```bash
<<EOF
这是一个多行注释
可以包含多行内容
EOF
```
在C/C++等编程语言中,多行注释通常使用“/*”和“*/”符号进行标记:
```c
/*
这是一个多行注释
可以包含多行内容
*/
```
在Python等编程语言中,多行注释可以使用三个引号(单引号或双引号)进行标记:
```python
'''
这是一个多行注释
可以包含多行内容
'''
```
注释在Linux中起着重要的作用,它们可以帮助开发人员理解代码、调试代码并进行文档编写。
因此,在编写代码时,注释的使用是一个良好的编程习惯。
鲁瑞彬 linux内核启动项中英文注释 grub.cfg
![鲁瑞彬 linux内核启动项中英文注释 grub.cfg](https://img.taocdn.com/s3/m/32fcac160b4e767f5acfceb7.png)
# #其中加#的均为注释项# DO NOT EDIT THIS FILE# 不能编辑的程序文档(说明此文档涉及启动项,为系统文件,不能随意编译)# It is automatically generated by /usr/sbin/grub-mkconfig using templates#它会自动通过/ usr / sbin / grub-mkconfig使用生成的模板# from /etc/grub.d and settings from /etc/default/grub#从/ etc / grub.d和从/ etc /defaule/grub设置### BEGIN /etc/grub.d/00_header ######从etc/grub.d/00_heade目录下开始if [ -s /boot/grub/grubenv ]; then #配置开机启动项have_grubenv=trueload_envfiset default="6"#默认为6(已经修改,即默认启动项为windowsXP)if [ ${prev_saved_entry} ]; thensaved_entry=${prev_saved_entry}save_env saved_entryprev_saved_entry=save_env prev_saved_entryfiinsmod ext2#除了用作启动的分区外,其他分区格式可在menu底下再添加set root=(hd0,8) #设定root分区search --no-floppy --fs-uuid --set a60b11f3-d477-4121-8914-d1e1e0159851 #设定uuid=****的分区为rootif loadfont /usr/share/grub/unicode.pf2 ; then#设置终端字体,unicode.pf2支持中文显示set gfxmode=640x480#设置分辨率,默认为 640x480insmod gfxterm#插入模块 gfxterm,支持中文显示insmod vbe#插入 vbe 模块if terminal_output gfxterm ; then true ; else#设置 GRUB 2 终端为 gfxterm# For backward compatibility with versions of terminal.mod that don't # understand terminal_output terminal gfxtermfifiif [ ${recordfail} = 1 ]; thenset timeout=-1#设置超时时间为1Selseset timeout=10#设置超时时间为10Sfi### END /etc/grub.d/00_header ###### BEGIN /etc/grub.d/05_debian_theme ###set menu_color_normal=white/blackset menu_color_highlight=black/white#这两行设置Debian 下的菜单颜色### END /etc/grub.d/05_debian_theme #### 10_linux 为自动添加的当前root分区linux引导项### BEGIN /etc/grub.d/10_linux ####菜单项,要包括 menuentry 双引号" " 和大括号 { }才完整,否则不显示菜单menuentry "Ubuntu, Linux 2.6.31-14-generic"{recordfail=1if [ -n ${have_grubenv} ];then save_env recordfail;fiset quiet=1insmod ext2set root=(hd0,8)search --no-floppy --fs-uuid --seta60b11f3-d477-4121-8914-d1e1e0159851#这句与set root=(hd0,7)重复,课删除linux /boot/vmlinuz-2.6.31-14-genericroot=UUID=a60b11f3-d477-4121-8914-d1e1e0159851 ro quiet splashinitrd /boot/initrd.img-2.6.31-14-generic}menuentry "Ubuntu, Linux 2.6.31-14-generic (recovery mode)" {recordfail=1if [ -n ${have_grubenv} ];then save_envrecordfail;fiinsmod ext2set root=(hd0,8)search --no-floppy --fs-uuid --set a60b11f3-d477-4121-8914-d1e1e0159851linux /boot/vmlinuz-2.6.31-14-genericroot=UUID=a60b11f3-d477-4121-8914-d1e1e0159851 ro single initrd /boot/initrd.img-2.6.31-14-generic}### END /etc/grub.d/10_linux #### 自动添加存在于其他分区的系统引导项### BEGIN /etc/grub.d/20_memtest86+ ### #linux 启动菜单menuentry "Memory test (memtest86+)"{linux16 /boot/memtest86+.bin}menuentry "Memory test (memtest86+, serial console 115200)" {linux16 /boot/memtest86+.binconsole=ttyS0,115200n8}### END /etc/grub.d/20_memtest86+ ####结束标志### BEGIN /etc/grub.d/30_os-prober ####下面为Windows 启动菜单menuentry "Windows XP (on /dev/sda1)"{insmod fatset root=(hd0,1)search --no-floppy --fs-uuid --set 487a-e45ddrivemap -s (hd0) ${root}chainloader +1}### END /etc/grub.d/30_os-prober ###### BEGIN /etc/grub.d/40_custom #### 以下为手动添加的菜单项entries. Simply type the# menu entries you want to add after this comment. Becareful not to change# the 'exec tail' line above.### END /etc/grub.d/40_custom ###。
linux 命令的中文手册
![linux 命令的中文手册](https://img.taocdn.com/s3/m/9528ef505e0e7cd184254b35eefdc8d376ee14d1.png)
linux 命令的中文手册
Linux命令的中文手册是Linux系统中非常重要的资源,它提
供了关于各种命令的详细信息和用法说明,帮助用户更好地理解和
使用Linux系统。
Linux命令的中文手册通常以man(manual)命令
的形式提供,用户可以通过在终端中输入"man 命令名"来查看相应
命令的手册。
Linux命令的中文手册主要包括以下内容:
1. 命令的功能和作用,手册会详细介绍每个命令的功能和作用,帮助用户理解该命令可以完成的任务。
2. 语法和选项,手册会列出命令的语法结构和可用的选项,用
户可以根据手册了解命令的正确使用方法。
3. 示例和实例,手册通常会提供一些示例和实例,演示命令的
具体用法,帮助用户更好地理解命令的实际操作过程。
4. 相关说明和注意事项,手册还会包含一些相关说明和注意事项,帮助用户避免一些常见的错误使用情况。
用户可以通过man命令查看Linux命令的中文手册,比如要查
看ls命令的手册,可以在终端中输入"man ls"。
手册通常分为多个
部分,用户可以通过按下"q"键来退出手册的查看。
此外,还有一些在线资源和文档提供了Linux命令的中文手册,用户可以通过搜索引擎或者Linux系统自带的帮助文档来获取相关
信息。
总之,Linux命令的中文手册对于用户学习和使用Linux系
统非常重要,可以帮助用户更好地理解和掌握各种命令的用法和功能。
Linux0.01内核源代码及注释
![Linux0.01内核源代码及注释](https://img.taocdn.com/s3/m/be3b1c11ed630b1c58eeb509.png)
Bootsect.s(1-9)!! SYS_SIZE is the number of clicks (16 bytes) to be loaded.! 0x3000 is 0x30000 bytes = 196kB, more than enough for current! versions of linux ! SYS_SIZE 是要加载的节数(16 字节为1 节)。
0x3000 共为1 2 3 4 5 60x7c000x00000x900000x100000xA0000system 模块代码执行位置线路0x90200! 0x30000 字节=192 kB(上面Linus 估算错了),对于当前的版本空间已足够了。
!SYSSIZE = 0x3000 ! 指编译连接后system 模块的大小。
参见列表1.2 中第92 的说明。
! 这里给出了一个最大默认值。
!! bootsect.s (C) 1991 Linus Torvalds!! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves! iself out of the way to address 0x90000, and jumps there.!! It then loads 'setup' directly after itself (0x90200), and the system! at 0x10000, using BIOS interrupts.!! NOTE! currently system is at most 8*65536 bytes long. This should be no! problem, even in the future. I want to keep it simple. This 512 kB! kernel size should be enough, especially as this doesn't contain the! buffer cache as in minix!! The loader has been made as simple as possible, and continuos! read errors will result in a unbreakable loop. Reboot by hand. It! loads pretty fast by getting whole sectors at a time whenever possible.!! 以下是前面这些文字的翻译:! bootsect.s (C) 1991 Linus Torvalds 版权所有!! bootsect.s 被bios-启动子程序加载至0x7c00 (31k)处,并将自己! 移到了地址0x90000 (576k)处,并跳转至那里。
linuxman手册中英文对照
![linuxman手册中英文对照](https://img.taocdn.com/s3/m/4bda7e4ccd1755270722192e453610661ed95a3f.png)
以下是一些常见的Linux命令及其对应的英文解释:
1.ls:list,列出目录中的文件和文件夹。
2.cd:change directory,改变当前目录。
3.pwd:print working directory,打印当前工作目录。
4.cp:copy,复制文件或文件夹。
5.mv:move,移动文件或文件夹,或重命名文件或文件
夹。
6.rm:remove,删除文件或文件夹。
7.touch:touch,创建一个空文件,或更新文件的访问和
修改时间戳。
8.cat:concatenate and display,显示文件内容,或连接
多个文件。
9.grep:global regular expression print,在文件中搜索
匹配正则表达式的文本。
10.find:find file,在目录树中搜索文件。
11.sort:sort lines of text,对文本行进行排序。
12.wc:word count,统计文本中的行数、字数和字符数。
13.echo:echo,显示文本或变量的值。
14.man:manual,显示命令的手册页。
15.exit:exit,退出shell。
Linux常用命令英文全称与中文解释(Linux入门)
![Linux常用命令英文全称与中文解释(Linux入门)](https://img.taocdn.com/s3/m/2df0a81e77c66137ee06eff9aef8941ea76e4b45.png)
Linux常⽤命令英⽂全称与中⽂解释(Linux⼊门)man: Manual 意思是⼿册,可以⽤这个命令查询其他命令的⽤法,例:man ls查看ls命令的⽤法和详解.(command --help或command -h也可以查看command命令的详解)ls: List files 列出当前⽬录下的⽂件(linux中⼀切皆⽂件)lsmod:List module,列出linux中加载的模块列表lscpu:List cpu,列出linux的cpu信息. CPU(Center Processing Unit)中央处理单元lsmem:List memory,列出linux的内存信息lsattr:List attribute,列出⽂件的属性信息pwd: Print working directory显⽰当前所在的⽬录(以绝对路径显⽰)cd: Change directory 切换⽬录,后⾯跟要进⼊的⽬的⽬录,⽬录路径可以⽤相对路径和绝对路径表⽰,后⾯不跟选项和参数时和cd ~命令可以⼀样回到当前登录⽤户的家⽬录。
cd -表⽰进⼊上次进⼊⽬录的位置,cd -连续使⽤即两个⽬录来回切换。
cd ..表⽰进⼊当前⽬录的上⼀级⽬录,例:当前⽬录为/root,使⽤cd ..命令后会回到/⽬录(/表⽰根⽬录,也是Linux⽬录结构的顶级⽬录)su:Switch user,切换⽤户(su - user1和su user1都能切换到user1,但尽量不要使⽤后者,因为后者只是shell层⾯上的切换,切换后⽤户的环境变量还是之前⽤户的)cat: Con cat enate 串联,在linux中主要查看⽂件的内容passwd:password的缩写,直接使⽤passwd命令,即命令后不跟选项和参数时表⽰更改当前登录⽤户的密码touch: 创建⽂件的命令,例:touch 1.txt为创建⼀个1.txt的普通⽂件,但touch命令后⾯跟的⽂件是当前存在的⽂件,那么会更新该⽂件的时间戳stat:stat us,命令后边跟⽂件,即可查看⽂件的时间戳等信息mkdir: mk=Make,dir=directory,意为创建⼀个⽬录(即⽂件夹)ln: Link 创建⼀个链接⽂件,⼀般使⽤-s参数,指创建⼀个软连接(相当于Windows⾥的快捷⽅式)mv: move,移动⽂件,也可以修改⽂件名。
linux filelist的注释
![linux filelist的注释](https://img.taocdn.com/s3/m/1e25aad518e8b8f67c1cfad6195f312b3169ebb0.png)
linux filelist的注释1. 文件权限(File Permissions)文件权限在Linux系统中是非常重要的,它决定了用户对文件的访问权限。
在文件列表中,我们可以看到每个文件的权限设置,如"rwxr-xr-x"。
其中,第一位表示文件类型,如"-"表示普通文件,"d"表示目录,"l"表示符号链接。
接下来的三位表示文件所有者的权限,再接下来的三位表示文件所属组的权限,最后的三位表示其他用户的权限。
每一位的含义是:r表示读取权限,w表示写入权限,x表示执行权限。
2. 文件所有者和所属组(File Owner and Group)文件列表中显示了每个文件的所有者和所属组。
所有者是创建或拥有该文件的用户,而所属组是指该文件所属的用户组。
文件的所有者可以通过权限设置来决定文件的访问权限,而所属组可以决定一些特殊权限,如组权限。
这些信息对于文件的管理和权限控制非常重要。
3. 文件大小(File Size)文件列表中还显示了每个文件的大小。
文件大小以字节为单位,可以帮助我们判断文件的占用空间以及文件的类型。
在查找大文件、空文件或者计算磁盘空间时,文件大小是一个非常有用的信息。
4. 文件创建时间(File Creation Time)文件列表中还包含了每个文件的创建时间。
这个信息可以帮助我们追踪文件的创建历史,了解文件的版本信息以及判断文件的更新时间。
对于文件的备份、恢复和版本控制等操作,文件的创建时间是一个重要的参考。
5. 文件名称(File Name)文件列表中的文件名称显示了每个文件的唯一标识符。
文件名称可以包含字母、数字、特殊字符和文件扩展名等信息。
在查找、复制、重命名或删除文件时,文件名称是一个重要的参考。
6. 文件路径(File Path)文件列表中的文件路径显示了每个文件所在的目录路径。
文件路径是一个由目录名称和文件名称组成的字符串,可以帮助我们定位和访问文件。
linux知识点整理
![linux知识点整理](https://img.taocdn.com/s3/m/ef400e8076eeaeaad0f33015.png)
Linux实用教程第一章⏹Linux是在GPL(General Public License,通用公共许可证)版权协议下发行的操作系统,是一种类Unix的操作系统,其版权属于Linus Torvalds.⏹GNU是“GNU's Not Unix”的递归缩写。
Stallman宣布GNU应当发音为Guh-NOO以避免与new这个单词混淆(注:Gnu在英文中原意为非洲牛羚,发音与new相同)。
UNIX是一种广泛使用的商业操作系统的名称。
由于GNU将要实现UNIX系统的接口标准,因此GNU计划可以分别开发不同的操作系统部件。
GNU计划采用了部分当时已经可自由使用的软件,例如TeX排版系统和X Window视窗系统等。
不过GNU 计划也开发了大批其他的自由软件。
⏹Linux的应用主要有4个方面:服务器、嵌入式、软件开发、桌面应用。
Linux的长处主要在于服务器端和嵌入式两个领域。
⏹Linux系统的特点:1.开放性2.多用户3.多任务4.良好的用户界面5.设备独立性6.丰富的网络功能7.可靠的系统安全8.良好的可移植性⏹Linux系统一般有4个主要部分:内核、Shell、文件系统、应用程序。
内核版本是在Linus领导下的开发小组开发出的系统内核版本号,由三个数字组成kernel的主版本号x: 次版本号,偶数:表示稳定版本;奇数:开发中版本y: 修正号,表示错误修补次数。
如:稳定版本; 测试版本:什么是发行版本:答:一些组织和厂家,将Linux系统的内核、应用软件和文档包装起来,并提供安装界面、系统配置管理工具等,就构成了Linux发行版本。
第二章Linux通过字母和数字的组合来标识硬盘分区,如“hda1”,其具体含义是:前两个字母表明分区所在设备的类型,例如hd指IDE硬盘,sd指SCSI硬盘;第三个字母表示分区所在的设备,如/dev/hda表示第1个IDE硬盘,/dev/sdb表示第2个SCSI硬盘。
Linux启动脚本完全注释2---rc脚本注释
![Linux启动脚本完全注释2---rc脚本注释](https://img.taocdn.com/s3/m/8d8c4cd34128915f804d2b160b4e767f5acf8099.png)
Linux启动脚本完全注释2---rc脚本注释从/etc/inittab中可以看出,启动的核⼼就是rc脚本.⾸先init程序调⽤rc脚本,并将级别传递给rc脚本.其次rc脚本去调⽤该级别内(/etc/rcX.d)各项服务的脚本.rc脚本的注释如下:#!/bin/sh######################################################################### Begin $rc_base/init.d/rc## Description : Main Run Level Control Script## Authors : Gerard Beekmans - gerard@## Version : 00.00## Notes :#########################################################################./etc/sysconfig/rc #指定rc_bash=/etc/rc.d rc_functions =${rc_bash}/init.d/ functions network_devices=/etc/sysconfig/network-devices.${rc_functions}# This sets a few default terminal options.stty sane# These 3 signals will not cause our script to exittrap "" INT QUIT TSTP #trap是bash内建的命令,⽤来指定信号的⾏为,“”为忽略该信号[ "${1}" !="" ] && runlevel=${1} #从参数中得到运⾏级别,在/etc/inittab中指定的if [ "${runlevel}"="" ];then#运⾏级别为空则退出echo"Usage: ${0} <runlevel>">&2exit1fiprevious=${PREVLEVEL} #前⼀个级别[ "${previous}"="" ] && previous=N #没有前⼀级别则为nif [ ! -d ${rc_base}/rc${runlevel}.d ];then#是否有该级别的⽬录boot_mesg "${rc_base}/rc${runlevel}.d does not exist."${WARNING}boot_mesg_flushexit1fi# Attempt to stop all service started by previous runlevel,# and killed in this runlevel#结束该级别中K开头的脚本if [ "${previous}" !="N" ];then#如果有前⼀个级别for i in $(ls -v ${rc_base}/rc${runlevel}.d/K* 2>/dev/null)docheck_script_statussuffix=${i#$rc_base/rc$runlevel.d/K[0-9][0-9]} #脚本的名称,除去路径和K** prev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffix #前⼀级别sysinit_start=$rc_base/rcsysinit.d/S[0-9][0-9]$suffix #系统初始化if [ "${runlevel}" !="0" ] && [ "${runlevel}" !="6" ];then#不是重启和关机if [ ! -f ${prev_start} ] && [ ! -f ${sysinit_start} ];then#如果不存在boot_mesg -n "WARNING: ${i} can't be"${WARNING} #前⼀级别并没有启动该脚本boot_mesg -n " executed because it was not"boot_mesg -n " not started in the previous"boot_mesg -n " runlevel (${previous})."boot_mesg ""${NORMAL}boot_mesg_flushcontinuefifi${i} stop #脚本执⾏stoperror_value=${?} #返回值if [ "${error_value}" !="0" ];thenprint_error_msgfidonefi#Start all functions in this runlevel#开始所有S开头的脚本for i in $( ls -v ${rc_base}/rc${runlevel}.d/S* 2>/dev/null)#获得每个脚本doif [ "${previous}" !="N" ];then#如果有前⼀个级别suffix=${i#$rc_base/rc$runlevel.d/S[0-9][0-9]} #脚本⽂件名stop=$rc_base/rc$runlevel.d/K[0-9][0-9]$suffixprev_start=$rc_base/rc$previous.d/S[0-9][0-9]$suffix[ -f ${prev_start} ] && [ ! -f ${stop} ] && continue #如果前⼀个级别中没有该脚本的stop,则说明该进程已经存在ficheck_script_status #检查脚本是否存在case ${runlevel} in #0或6则直接stop0|6)${i} stop;;*)${i} start;;esacerror_value=${?}if [ "${error_value}" !="0" ];thenprint_error_msgfidone#End$rc_base/init.d/rc。
Linux内核0.11体系结构——《Linux内核完全注释》笔记打卡
![Linux内核0.11体系结构——《Linux内核完全注释》笔记打卡](https://img.taocdn.com/s3/m/434b42feafaad1f34693daef5ef7ba0d4a736df9.png)
Linux内核0.11体系结构——《Linux内核完全注释》笔记打卡0 总体介绍⼀个完整的操作系统主要由4部分组成:硬件、操作系统内核、操作系统服务和⽤户应⽤程序,如图0.1所⽰。
操作系统内核程序主要⽤于对硬件资源的抽象和访问调度。
图0.1 操作系统组成部分内核的主要作⽤是为了与计算机硬件进⾏交互,实现对硬件部件的编程控制和接⼝操作,调度对硬件资源的访问,并为计算机上的⽤户程序提供⼀个⾼级的执⾏环境和对硬件的虚拟接⼝。
1 Linux内核模式操作系统内核的结构模式主要可分为整体式的单内核模式和层次是的微内核模式。
Linux 0.11采⽤了单内核模式。
如图1.2所⽰,单内核操作系统所提供的服务流程为:应⽤主程序使⽤指定的参数值执⾏系统调⽤指令(int x80),使CPU从⽤户态切换到核⼼态,然后操作系统根据具体的参数值调⽤特定的系统调⽤服务程序,这些服务程序根据需要再调⽤底层的⼀些⽀持函数以完成特定的功能。
完成服务后,系统使CPU从核⼼态回到⽤户态,执⾏后续的指令。
图1.1 单内核模式的简单模型结构2 Linux内核系统体系结构Linux内核主要由5个模块构成,分别为:进程调度模块、内存管理模块、⽂件系统模块、进程间通信模块和⽹络接⼝模块。
模块之间的依赖关系如图2.1所⽰,虚线部分表⽰0.11版本内核中未实现部分(所有的模块都与进程调度模块存在依赖关系)。
图2.1 Linux内核系统模块结构及相互依赖关系从单内核模式结构模型出发,Linux 0.11内核源代码的结构将内核主要模块分配如图2.2所⽰。
(除了硬件控制⽅框,其他粗线分别对应内核源代码的⽬录组织结构)图2.2 内核结构框图3 Linux内核对内存的管理和使⽤对于机器中的物理内存,Linux 0.11内核中,系统初始化阶段将其划分的功能区域如图3.1所⽰。
图3.1 物理内存使⽤的功能分布图虚拟地址:(virtual address)由程序产⽣的由段选择符合段内偏移地址两个部分组成的地址。
Linux命令手册大全
![Linux命令手册大全](https://img.taocdn.com/s3/m/535dff691ed9ad51f01df27e.png)
3.15寻找文件 命令:find 格式:find pathname [option] expression 功能:在所给的路经名下寻找符合表达式相匹配的文件。 选项:-name 表示文件名 -user 用户名,选取该用户所属的文件 -group 组名,选取该用户组属的文件 -mtime n 选取 n 天内被修改的文件 -newer fn 选取比文件名为 fn 更晚修改的文件 注释: 例如:% find . -name '*abc*' -print 3.16搜索文件中匹配符 命令:grep 格式:grep [option] pattern filenames 功能:逐行搜索所指定的文件或标准输入,并显示匹配模式的每一行。 选项:-v 找出模式失配的行 -c 统计匹配行的数量 -n 显示匹配模式的每一行 注释: 例如:% ps -aux | grep R 3.17比较文件不同 命令:diff (difference) 格式:diff filename1 filename2 功能:显示两文件的不同之处。 选项: 注释: 例如:% diff file1 file2 3.18比较文件 命令:cmp (compare) 格式:cmp [-l] [-s] filename1 filename2 功能:显示比较两文件不同处的信息 选项:-l 给出两文件不同的字节数 -s 不显示两文件的不同处,给出比较结果 注释: 例如:% cmp file1 file2 3.19比较文件共同处 命令:comm (common) 格式:comm [-123] filename1 filename2 功能:选择或拒绝比较两文件出现的共同行 选项:-1 不显示第1列 -2 不显示第2列
Linux源代码的注释
![Linux源代码的注释](https://img.taocdn.com/s3/m/b68d02601ed9ad51f01df2c7.png)
在接下来的几天里面,我将陆续贴出我自己对Linux源代码的注释,本来打算只在我们校园网上发表,但是发现我们学校学习Linux源代码的人不是很多于是就来到这里。
因为我不是什么高手,所以在注释过程中难免有错误和出入。
还请多多包涵。
前面我在Linux下发这个贴子的时候发现在Linux下的Mozilla网页浏览器下根本不能发表新帖子,写正文的这个文档框始终处于不可写状态。
而我的注释内容是在Linux下编辑的,在window下更本打不开,所以先发这个帖子,然后回到Linux下一张一张的贴上去。
接触Linux内核已有一段时间了,算是对操作系统有了那吗一点点的认识,今天突然心血来潮,想把自己学的一点东西写出来.于是便来到了论坛,小可学艺未精,不当之处还请包涵.下面先说一下操作系统存在的基础或理由:计算机中最重要和最智能化的硬件部件是中央处理器(CPU),为什么这么说呢?原因是CPU提供了一套最基本的指令集,这个东西(指令集)是计算机能够进行数据处理的基础.举个例子,当你进行c语言编程时有一条最简单的赋值语句x=3,它是怎么被计算机执行的呢?在计算机的CPU内部他是把3这个数送入x所在的内存单元,其中最重要的”送”这个命令是谁发出的呢?就是CPU的电子脉冲,CPU 里面定义了很多这样的电子脉冲,比如'加'指令的电子脉冲,”跳转”指令(实现循环)的电子脉冲等.而这些电子脉冲合起来就是所谓的CPU指令集.它定义了计算机内部最基本的运算方式,计算机的所有的算法最后都被分解成这些最基本的运算方式,就像是数学上不管怎么难的算式最后都分解成加法,减法,乘法,除法等最基本的算式一样.利用这些指令集定义的最基本的算法构建的更为复杂的算式就是所谓的计算机软件,操作系统以是一种软件,以是一大堆最基本的指令集的组合.只不过它是管理其它软件的软件,如果把操作系统看比做物理上的公式的话,那么一般的应用软件就好像是套用这公式的数据一样.现在应该知道操作系统存在的基础和理由了吧!下面就开始说操作系统的部分了:操作系统是由一大堆基本指令组成的更为复杂的程序,一般操作系统都是用c语言的编写的,c语言编写的操作系统在安装是被编译器编译成二进制代码存放在计算机的硬盘当中,计算机打开电源的时候被读入内存,然后就由操作系统利用自己的程序控制整个计算机的软件和硬件.操作系统是怎么控制整个计算机的软硬件的呢,当然是通过它自己的程序来控制计算机的,现在讨论的问题是操作系统通过什么样的程序来控制计算机的.总的来说操作系统分为五大部分:进程管理,内存管理,文件管理,网络管理,设备管理.下面就以这五部分为总纲,我有一一道来:进程管理:什么是进程,大家都用过计算机,知道什么是计算机程序.我们说写在纸上或者存储在计算机的硬盘上的一段代码就是程序.那什么是进程呢?我们说在计算机上运行的程序就是进程.那进程和程序和什么区别呢?程序是写在纸上或者是存储在计算机硬盘上一段”死”的代码,当这段代码进入计算机内存被计算机执行的时候就变成了进程,进程是”活”的东西.因为进程是在计算机中被执行的程序,所以它比程序要多考虑的东西就是计算机内部的运行环境.在操作系统中进程和任务是同一个概念.我们用的操作系统基本上都是多任务操作系统(window/Linux在同一时间有多个进程运行),那么这么多进程是怎么同时在CPU上运行的哪?这就是进程管理要解决的问题.在计算机中要执行一个程序,首先将程序的代码从硬盘读入到内存,然后CPU 根据程序代码指令一条一条的执行,而这时候的程序就叫进程,计算机中同时存在多个进程在等待被执行,比如你在用window/Linux上网的时候,你一边用QQ和朋友聊天,一边在用MP3播放器听音乐,一边在浏览网页.那么这时候在计算机中就有三个进程在同时运行,一是QQ进程,二是MP3播放器进程,三是浏览器进程.但是计算机中只有一个CPU,在一个时间点上,它只能运行一个进程的指令,比如在2005/11/29/日08/23/42/秒时计算机的CPU执行的是QQ进程的一条加法(mov)指令.那么计算机是怎样让三个进程同时运行起来的呢(至少我们看来是这样).在计算机内部所有的正在运行的进程都在等待被CPU执行,操作系统按一定的规律让所有的进程都得到CPU的执行.方法是一会儿让QQ进程执行,过了一定时间后又让MP3播放器进程得到CPU的执行,再过一定时间后让浏览器进程得到CPU的执行.相对于人的反应,CPU的执行速度太快,所以人根本感觉不到这些进程的切换过程,也不会对人的操作产生影响,现在的问题是操作系统是按照什么样的规律给个各进程分配CPU资源的.操作系统是按照个各进程的属性来分配CPU资源的.那进程的属性在什么呢?当操作系统创建一个进程时都就为这个进程分配了一定的内存空间来存放它的属性.在Linux操作系统中,操作系统定义了一个数据结构task_struct来描述各个进程的进程属性,task_struct结构叫进程控制块(PCB), 它是操作系统中重要的数据结构之一.具体定义在/include/linux/sched.h 中,注意在Linux操作系统中所有的操作系统源代码都在/usr/src目录下.task_struct结构的代码如下所示:(这里以2.40内核为准,可能不同版本的内核代码会有一点点的不同)(为了保持简洁,从宏关上把握,不拘泥于具体,这里只说一部分,其它的以后会讲到,这里只说功能)_________________/include/linux/sched.hstruct task_struct {volatile long state; /* 进程的状态,在代码后面有说明*/unsigned long flags; /* 进程标志*/int sigpending;mm_segment_t addr_limit; /* 线性地址空间:0-0xBFFFFFFF 为用户线性空间地址;0-0xFFFFFFFF 为内核线性空间地址*/ struct exec_domain *exec_domain;volatile long need_resched;unsigned long ptrace;int lock_depth;long counter; /* 进程的动态优先级,在代码后面有说明*/long nice; /* 进程的静态优先级,在代码后面有说明*/unsigned long policy; /* 进程采用的调度策略,在代码后面有说明*/struct mm_struct *mm; /* 进程属性中指向内存管理的数据结构mm_structd的指针,在代码后面有说明*/int has_cpu, processor;unsigned long cpus_allowed;struct list_head run_list;unsigned long sleep_time;struct task_struct *next_task , *prev_task; /* 所以进程通过这两个指针组成一个双向链表*/struct mm_struct *active_mm; /* 指向活动地址空间,在后面的代码有说明*//* task state */struct linux_binfmt *binfmt;int exit_code, exit_signal;int pdeath_signal;unsigned long personality;int did_exec:1;int dumpable:1;pid_t pid; /* 进程标志符,,在代码后面有说明*/pid_t pgrp; /* 进程组标号,,在代码后面有说明*/pid_t tty_old_pgrp;pid_t session;pid_t tgid;int leader;struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;/* 这五个标志表示一个进程的在计算机中的亲属关系,分别标志祖先进程,父进程,子进程,弟进程和兄进程,为了在两个进程之间共享方便而设立*/ struct list_head thread_group;struct task_struct *pidhist_next;struct task_struct *pidhist_pprev; /* 上面两个指针是为了在计算机中快速查一个进程而设立,具体方式以后讲*/wait_queue_head_t wait_chldexit;struct completion *vfork_sem;unsigned long rt_priority; /* 实时进程的优先级标志*/unsigned long it_real_value, it_prof_value, it_virt_value;unsigned long it_real_incr, it_prof_incr, it_virt_incr;struct timer_list real_timer;struct tms times;struct tms group_times;unsigned long start_time;long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;int swappable:1;uid_t uid,euid,suid,fsuid;gid_t gid,egid,sgid,fsgid;int ngroups;gid_t groups[NGROUPS];kernel_cap_t cap_effective, cap_inheritable, cap_permitted;int keep_capabilities:1;struct user_struct *user;struct rlimit rlim[RLIM_NLIMITS];unsigned short used_math;char comm[16];int link_count;struct tty_struct *tty; /* NULL if no tty */unsigned int locks; /* How many file locks are being held */struct sem_undo *semundo;struct sem_queue *semsleeping;struct thread_struct thread;struct fs_struct *fs; /* 进程属性中指向和文件管理有关的数据结构*/struct files_struct *files;spinlock_t sigmask_lock;struct signal_struct *sig;sigset_t blocked;struct sigpending pending;unsigned long sas_ss_sp;size_t sas_ss_size;int (*notifier)(void *priv);void *notifier_data;sigset_t *notifier_mask;u32 parent_exec_id;u32 self_exec_id;spinlock_t alloc_lock;spinlock_t switch_lock;};_____________________/include/linux/sched.h程序说明如下:volatile long state 定义了进程的状态,进程总共有6种状态标志,分别是:一. TASK_RUNING. (正在运行状态或者是可运行状态)二. TASK_INTERRUPTIBLE,(可打断睡眠状态)三. TASK_UNINTERRUPTIBLE,(不可打断睡眠状态)四. TASK_ZOMBLE. (僵死状态)五. TAKS_STOPPED.(暂停状态)六. 交换状态.这六种属性标志了此进程现在的状态,各种不同的状态决定了进程什么时候获得CPU而被执行.正在运行状态是当前正在运行进程的状态.也就是说他的volatile long state 被标志成TASK_RUANING.可运行状态是那些正在等待CPU资源的进程的状态,这些进程在就绪队列run-queqe中.这些进程只要得到CPU在个资源就马上可以被运行.其也被标志也为TASK_RUANING.可打断睡眠状态是哪些在等待队列中等待除CPU之外的其它资源的进程,只要它们所等待的资源到达就马上可以从等待队列进入就绪队列,其状态标志也从TASK_INTERRUPTIBLE状态变成TASK_RUANING可运行状态.不可打断睡眠状态和可睡眠状态类似,区别在于前者可以用信号唤醒,而后者不可以.僵死状态是标志那些已经运行完毕释放了大部分资源并退出但还没有释放进程控制快task_struct的进程.暂停状态是那些遇到突发情况或者收到暂停信号而暂时停止运行的进程的状态.counter是进程的动态优先级,它定义了一个在就绪队列的进程当它得到CPU 后可运行的时间,用静态优先级初始化,当然计算机是以时钟中断做为时间的计数器,每发送一个时钟中断,动态优先级上的时间片就减少一个时钟中断的时间,时间片减到0的时候就退出该进程而调度另一个进程获得CPU.nice是进程的静态优先级,当一个在就绪队列中的进程获得CPU之后,它被赋予此进程可占有CPU的时间.这个时间被称为时间片.policy是进程的调度策略标志.有三种调度标志:SCHED_OTHER 普通进程的调度策略,基于优先权的轮转法.SCHED_FIFO 实时进程的调度策略,基于先进先出的算法.SCHED_RR 实时进程的调度策略,基于优先权的轮转法.在linux中有两种进程,一种是普通进程,一种的实时进程,实时进程的优先级总是高于普通进程,也就是说当就绪队列中即有实时进程也有普通进程时,总是先运行实时进程.不同的进程采用不同的调度策略.rt_priority 实时进程的优先级.need_resched 标志下一次有调度机会的时候是否调用此进程.如果此进程没有没有被用户关闭或者其代码全被执行完了,在下一次调度机会应该还被调用.如果被用户关闭则直接退出该进程.mm_struct *mm mm_struct数据结构是描述内存存储信息的数据结构,进程控制块task_struct中用mm指针指想mm_struct数据结构.也就是在进程的属性中通过mm指针来管理起对应的内存区.mm_struct *active_active 内核线程用来指向调用它的普通进程的内存地址空间.当普通进程在运行时如果发生系统调用,程序就会从用户态转为内核态,内核态中执行的是内核线程,内核线程没有内存空间地址结构mm_struct,当他需要内存空间地址的时候就会调用用户态对应进程的用以空间地址结构mm_struct.内核线程就是就是通过active_mm指针来指向用户态进程的mm_struct结构.pid_t pid pid是进程标志符,操作系统每创建一个新的进程就要为这个新进程分配一个进程控制快(PCB),那么系统内核是怎样区分这些进程的呢?就是通过进程标志符pid,系统在为新的进程分配进程控制块的候,它不是自己去创建,而是直接从上一个进程中复制它的进程控制块,其中里面的大部分东西保留下来,只做少量的改动,然后它的进程标志符加1赋值给新的进程控制块.进程控制块的总共有80多项,在这里就不一一介绍了,以后我们在学习过程用到什么属性就介绍什么属性,这样在宏观上把握,不至于被一个小小的进程控制块给挡住了.接着上面的进程说明,前面我们说了一下进程的基本概念和它的属性,接下来我们介绍一下在操作系统内部是怎样通过调度函数调度进程的.我们在使用计算机的时候,可能同时打开了很多程序,比如同时打开IE浏览器,QQ,word文档等,那么这就意味着内核要同时管理多个用户进程.这些进程中每个进程每隔一段时间就要被CPU执行一次,所有的进程都是这样轮流执行,在Linux操作系统中一个进程占有CPU的时间为50ms(也就是5个时间滴答,关于时间滴答的概念后面介绍),这个时间对于人的反应来讲是相当快的,所以人更不感觉不到进程的调度和切换,各个进程也有轻重缓急之分,后面还会说一个goodness 函数,这个函数比较简单,主要作用是综合进程属性(进程控制快)中的各种因素和数据算出每个进程的权值,权值最大的进程就是调度程序(schedule())最应该调用的进程.在计算机中进程以六种状态存在,这在进程的属性里已经有了介绍,其中存在于就绪队列TASK_RUNNING中处于运行状态的进程是等待计算机中唯一的资源CPU的进程,它们只要一得到CPU就马上可以被执行,那么操作系统是安什么样的规则来让这些进程合理和公平的得到CPU的呢,这就要用到计算机的调度函数schedule(),__________________/kernel/sched.casmlinkage void schedule(void){struct schedule_data *sched_data;struct task_struct *prev, *next, *p;struct list_struct *tmp;int this_cpu,c;if(!current->active_mm) BUG(); /* current指当前进程,当前进程所指的内存空间,如果为空,那么进程必定有问题,出错返回*/need_resched_back:prev=current;this_cpu=prev->processor;if(in_interrupt())goto scheduling_in_interrupt;/*上面代码的意思是: 将局部变量prev和this_cpu初始化为当前进程和当前CPU.然后检查schedule()是否中断调用,若是则直接返回,其中goto后面的转到的地方在本程序中有定义,比如本进程后面的scheduling_in_interrupt在本程序的最后有定义,意思是: 打印出”Scheduling in interrupt”字符后退出*/release_kernel_lock(prev,this_cpu);if(softirq_active(this_cpu) & softirq_mask(this_cpu))goto handle_softirq; /* 检查是否有软中断请求,软中断softirq将在后面讲解*/hand_softirp_back:sched_data= & aligned_data[this_cpu].schedule_data;spin_lock_irp(&runqueue_lock);/* 局部变量sched_data中保存当前进程的数据区,*/if(prev->policy == SCHED_RR)goto move_rr_last;/ * 当前基于优先权轮转法的调度策略实时进程,如果要调用它,先检查其count是否0若是,则将其挂到运行队列的最后面.具体做法在后面的move_rr_last中有定义*/move_rr_back:switch(prev->state){case TESK_INTERRUPTIBLE:if(sign_pending(prev)){prev->state = TASK_RUNNING;break;}default:del_form_runqueue(prev);case TASK_RUNNING;}prev->need_resched=0;/* 上面这段代码意思是: 如果进程的状态为可中断睡眠状态且唤醒它的信号正在迫近, 则将其置为可运行状态,如果状态为运行状态则忽略,如果状态除上述两种之外的其它状态则直接删除.最后将neet_resched置为0,neet_resched置0意味着本能启动调度函数shchedule(); */repeat_schedule:next = idlt_task(this_cpu);c = -1000;if(prev->state == TASK_RUNNING)goto still_running;/* 上面的代码中的c是优先级运算函数goodness的一个变量,优先级运算函数goodness将是我们介绍的下一个函数,它的返回值是进程的权值,调度函数判断绪队列中权值最大的进程就是最优先要被调用的进程.goodness的具体算法看下一个函数.上面代码的意思是: 将next设置为当前cpu的idlt_task.将当前优先级的变量c赋值为-1000,其中-1000是goodness中最小的权值.然后判断当前进程是否是可运行进程,若是则转到still_running处执行,still_running在本函数的后面有解释.意思是: 将当前进程的goodness值赋予goodness优先级变量c并返回*/still_running_back:list_for_each(tmp,&runqueue_head){p = list_entry(tmp, struct task_struct, run_list);if(can_schedule(p,this_cpu))int weight = goodness(p,this_cpu,prev->active_mm);if(weight>c)c=weight,next=p;}/* 上面代码的意思是: 遍历整个就绪队列,计算出每一个进程的goodness权值并且与当前进程做比较,选择goodness权值最大的那个进程获得cpu资源. */ if(! c)goto recalculate;/* 上面代码的意思是: 如果当前goodness权值为0,则运行recalculate:,起代码在后面有说明,意思是:重新计算每一进程的优先权,最后转到repeat_schedule:处执行,repeat_schedule:部分在前面已经有讲过,自己看有会过头去看一下吧*/sched_data->curr = next; /* 将当前进程信息保存到局部变量sched_data 中*/#ifdef CONFIG_SMPnext->has_cpu = 1;next->processor = this_cpu;/* 意思为: 将调度数据区指针指向下一个要调度的进程并将当前进程的cpu设置为下一个进程的当前cpu. */#endifspin_unlock_irq(&runqueue_lock);if(prev == next)goto same_processor;/* 意思为: 如果当前运行的进程的goodness还是队列中所以进程中最高的,也就是说下一个要调度的进程还是当前进程.那么只要重新得到cpu控制权返回need_resched_back:处执行. */#ifdef CONFIG_SMPsched_data->last_schedule = get_cycles();#endifkstat.context_swtch ++;prepare_to_switch(){struct mm_struct *mm = next->mm;struct mm_struct *oldmm = prev->active_mm;if(! mm){if(next->active_mm) BUG();next->active = oldmm;atomic_inc(&old_mm->mm_count);enter_lazy_tlb(oldmm,next,this_cpu);}else{if(next->active_mm != mm) BUG();switch_mm(oldmm, mm, next, this_cpu);}if(! prev->mm){prev->active_mm = NULL;mmdrop(oldmm);}}switch_to(prev,next,prev);__scheduel_tail(prev);/* 上面的代码是进行进程切换*//* 下面的代码是前面代码中goto要转到的地方*/ same_processor:reacquire_kernel_lock(current);if(current -> need_resched)goto need_resched_back;return;recalculate:{struct task_struct *p;spin_unlock_irq(&runqueue_lock);read_lock(&tasklist_lock);fot_each_task(p)p->counter = (p->counter >>1) + NICE_TO_TICKS(p_nice);read_unlock(&tasklist_lock);spin_lock_irq(&runqueue_lock);}goto repeat_schedule;still_running:c = goodness(prev, this_cpu, precv->active_mm);next=prev;goto still_running_back;handle_softirq:do_softirq();goto handle_softirq_back;move_rr_last:if(! prev->counter){prev->counter = NICE_TO_TICKS(prev_nice);move_last_runqueue(prev);}goto move_rr_back;scheduling_in_interrupt:printf(“Scheduling in interrupt \n”);BUG();return();}在上面的我们说了进程调度程序schedule(),接着说一下上面的函数中用到的进程优先级的权值的运行函数googness();这个函数的作用很简单,就是算出就绪队列中的进程的优先级,然后调度程序调度优先级最高的进程获得当前CPU,计算机中进程分为两种,一为普通进程,它的优先级用进程控制块中的counter表示,二为实时进程,实时进程的优先级用rt_priority表示,它在进程控制块中有定义,当就绪队列中同时存在两种进程的时候,实时进程总是先于普通进程运行,它的实现机制是实时进程的权值以1000做为基础值,也就是说实时进程的权值是1000加上它的进程优先级,而普通进程的优先级就是它的进程优先级.整个函数比较简单,但却是操作系统内核最为频繁调用的函数之一,也直接关系到操作系统的性能.此函数如下:_____________________________/kernel/sched.cstatic inline int goodness(struct task_struct * p, int this_cpu,struct mm_struct this_mm)int weigth;weight=-1;/ * 定义函数返回的权值weight并进行初始化*//* 下面是普通进程的处理情况*/if(p->****** & SCHED_YIELD){goto out;/ * 如果要放弃本次调度,则直接返回, 转到的out处在后面有定义*/if(p->policy == SCHED_OTHER)weight = p-> counter;if(!weight)goto out;/* 函数是普通进程的情况,在这种情况下,进程的权值直接为本进程的剩余时间,如果剩余时间不存在或为0,则直接返回*/#ifdef CONFIG_SMPif(p->processor == this_cpu)weight += PROC_CHANGE_PENALTY;#endifif(p->mm == this_mm || !p->mm)weight +=1;weight +=20-p->nice;goto out;}/* 下面是实时进程的处理情况*/weight = 1000 + p->re_priority;/* 实时进程的权值至少为1000,也就说它的权值是它是基数1000加上实时进程的优先级,其中实时进程的优先级用re_priority表示,re_priority在进程的属性中有定义,out:return weight;/* 前面的代码中有调用*/}_____________________________/kernel/sched.c前面我们说了关于进程的概念,属性以及调度它的函数.接下来我们讲一下进程的创建,进程创建就是当系统接收到一个要求创建进程的信号时,系统为新进程所做的一系列工作.比如当你在使用计算机上网的时候如果打开了QQ聊天的服务程序的话.当你点击QQ图标的时候,系统就接收到了一个创建QQ进程的信号,接下来系统就要做一系列的工作来完成这个过程,这就是我们下面要讲的内容: 基础创建.创建进程的系统调用函数(系统调用是下一个要讲的内容)有三个,它们分别是:sys_fork(), sys_clone(), sys_vfork().由它们三个函数来完成进程的创建,这三个函数都比较简单,它们只是都同时调用了一个函数do_fork(),由于前面三个函数都比较简单,我们在后面讲,我们先讲一下do_fork()函数,这才是创建进程的主体.它被前面三个函数调用.________________________________/kernel/fork.cint do_fork(unsigned long clone_flags, unsigned long stack_start,struct pt_regs, unsigned long stack_size){int retval = -ENOMEN;struct task_struct *p;DECLARE_MUTEX_LOCKED(sem);if(clone_flags & CLONE_PID)if(current->pid)return -EPERM;/* 上面这段代码的意思是: 如果clone_flags的CLONE_PID置位,则除非是0号进程,否则将返回错误信息EPERM. clone_flags的定义将在后面介绍,0号进程就是操作系统启动时创建的第一个进程.上面的代码中if(current->pid)要成立,除非是0号进程.其中pid是进程标志符*/current->vfork_sem = &sem;p=alloc_task_struct();if(! p)goto fork_out;/ * 上面代码的意思是: 申请一个新的内存控制块,其中alloc_task_struct是在/include/asm_i386/process.h中的宏定义:#define alloc_task_struct() ((struct task_struct * ) _get_free_pages(GFP_KERNEL, 1))其中_get_free_pages是要申请两个页面,页面是内存管理的有关内容,这儿大家只要一个页面占4个字节就可以了.两个页面就是8个字节,而大家查一下进程控制块的大小就可以知道它只有1600KB左右,有就时说它只有1M左右,那么还剩下将近6.5M的空间去有什么用呢?其实剩余的空间是作为内核栈空间.至于内核栈的内容以后会讲到,但是如果申请内存空间失败则直接栈道fork_out处执行,fork_out在后面有定义*/*p = * current;/ * 代码意思: 前面申请了一个存放进程控制块的内存空间,接下创建新进程的进程控制块的内容,具体做法是先直接将其父进程的进程控制块的内容复制过来,再在后面对需要更新的部分做一些必要的赋值*/retval= -EAGAIN;if(atomic_read(&p->user->processor) >= p->rlim[RLIMIT_NPROC].rlim_cur)goto bad_fork_free;atomic_inc(& p->user->_count);atomic_inc(& p->user->processes);/* 上面代码的意思: 如果父亲进程已经用了用户进程,则修改p->user->_count和p->user->processes,将其数目加1,当然除非用户进程的RLIMIT_NPROC已经超过额定数目,如果你对代码不理解,那就先不要理解了,等你学完后面的代码时就能理解了*/if(nr_threads >= max_threads)goto bad_fork_cleanup_count;/* 上面的代码的意思是: 如果计算机中的进程的最大的进程数大于系统限定的最大数目就返回错误信号*/get_exec_domain(p->exec_domain);if(p->binfmt && p->binfmt->module)p->did_exec=NULL;p->swappable=NULL;p->state = TASK_UNINTERRUPTIBLE;/ * 上面的代码比较简单: 其中p是指向进程控制块task_struct的指针,did_exec和swappable以及state都在进程控制块中有定义,是对进程的这三个属性进行赋值,其意思如下:did_exec标志的意思是: 此进程是否被执行.swappable标志的意思是: 此进程占有的内存页面是否可以被换出到交换空间.state在前面有讲过.那么上面代码的意思是刚创建的进程没有被执行并且内存空间页面不可以被换出内存,当前状态设置为不可打断睡眠状态*/copy_flags(clone_flags, p);p->pid = get_pid(clone_flags);/ * 上面代码涉及到进程控制块中的进程标志flags,在task_struct中有定义,flags的意思是进程中有一些特殊的时候要靠它来决定进程调度函数的调度,上面的意思是: 将传进来的参数clone_flags通过copy_flags()函数转化为子进程的进程标志flags, 然后为新的子进程创建一个进程标志符pid */p->run_list.next=NULL;p->run_list.prev=NULL;/ * 对进程队列run_list进行初始化,进程队列run_list以后将*/if((clone_flags & CLONG_VFORK) || ! (clone_flags & CLONG_PARENT)) {p->p_opptr = current;if(! (p->ptrace & PT_PTRACED))p->p_pptr = current;}/ * 前面我们说过创建新进程的系统调用函数有三个,分别是sys_fork,sys_vfork,ys_clone.上面的意思是: 如果使用的sys_vfork()函数调用创建函数或者传人的参数clone_flags的CLONE_PARENT位为1,则将子进程的的p_opptr()指针指向当前进程.其中p_opptr指针在进程控制块task_struct中有定义,意思是它指向进程的祖先进程.如果ptrace的PT_PTRACED不为1,则将进程的指向父进程的指针指向当前进程.其中p_pptr是进程指向其父亲进程的指针,同样在进程控制块task_struct 中有定义* /p->p_cptr = NULL;/ * 进程的p_cptr指针指向它的儿子进程,在这里初始化为NULL * /init_waitqueue_head(&p->wait_chldexit);/ * 意思是: 初始化等待队列,等待队列是就绪队列一个基础,等待队列的进程当它得到它等待的资源(除CPU资源,CPUs是就绪队列中的进程等待的资源)后马上进入就绪队列,等待调度函数的调用以获得CPU资源* // * 下面所以的代码都是对进程控制块task_struct一些变量做一些初始化,这儿先就不过多的介绍了,现在只要知道有这些东西就行了* /p->vfork_sem=NULL;spin_lock_inin(& p->alloc_lock);p->sigpending = 0;init_sigpending(& p->pending);p->it_real_value = p->it_virt_value =p->it_prof_value = 0;p->it_real_incr = p->it_virt_incr= p->it_prof_incr =0;init_timer(&p->real_timer);p->real_timer.data = (unsigned long) p ;p->leader = 0;p->tty_old_pgrd = 0;p->times.tms_utime = p->times.tms_stimes = 0;p->times.tms_cutime= p->times.tms_cstime = 0;# ifdef CONFIG_SMP{int i;p->has_cpu = 0;p->proessor = current->proessor;for(i=0; i<smp_num_cpus ; i++)p->per_cpu_utime = p->per_cpu_stime =0;spin_lock_init(& p->sigmask_lock);}endifp->lock_depth = -1;p->start_time = jiffies;/ * 初始化在此结束*/retval = -ENOMEN;if(copy_files(clone_flags, p))goto bad_fork_cleanup;if(copy_fs(clone_flags, p))goto bad_fork_cleanup_files;if(copy_sighand(clone_flags, p))goto bad_fork_cleanup_fs;if(copy_mm(clone_flags, p))goto bad_fork_cleanup_sighand;/ * 上面代码的意思是: 根据传人的参数clone_flags决定复制打开文件表,文件系统信息,信号处理句柄和存储信息管理(上面4个分别代表的信息)还是直接和父亲进程共享,仅仅将引用数加1 * /retval = copy_thread(0, clone_flags, stack_start, stack_size, p, reps);if(retval)goto bad_fork_cleanup_sighand;p->semundo = NULL;p->parent_exec_id = p->self_exec_id;p->swappable = 1;p->exit_signal = clone_flags & CSIGNAL;p->pdeath_signal = 0;p->counter = (current->counter +1) >>1;current->counter >>=1;/ * 将父亲进程的时间片加1再除2然后赋值给子进程,同时将父亲进程的时间片减半* /if(! current ->counter)current->need_resched = 1;/ * 如果父亲进程的时间片减半后为0的话,直接将need_resched设置为1,need_resched在前面已经说过,它的意思是: 如果设置为1,下一此调度函数可以直接调度这个进程,但是如果设置为0则表示下一次调度函数不能调度此函数*/retval = pid;p->gpid = retval;INIT_LIST_HEAD(&p->thread_group);writh_lock_irq(&taslist_lock);if(clone_flags & CLONE_THREAD){p->tgid = current->tgid;list_add(&p->thread_group, ¤t->thread_group);}SET_LINKS(p);hash_pid(p);nr_threads ++;writh_unlock_irq(&tasklist_lock);if(p->ptrace & PT_PTRACED)send_sig(SIGSTOP, p, 1);wake_up_processor(p);++ total_forks;/ * 下面的前面goto代码要要转到执行的地方*/。
Linuxvim编辑器的批量注释
![Linuxvim编辑器的批量注释](https://img.taocdn.com/s3/m/7920a521b5daa58da0116c175f0e7cd184251843.png)
Linuxvim编辑器的批量注释
Linux vim编辑器的批量注释
批量注释
1. ⾸先打开要注释的⽂件,将光标调到要注释的那⼀⾏,使⽤Ctrl+v的⽅法进⼊块选择模式;
2. 然后按住光标上下移动,选择要注释的⾏;
3. 按shift + i进⼊⾏⾸输⼊模式;
4. 输⼊//进⾏注释(Linux下c编程)或者输⼊#进⾏注释(Linux下脚本编程);
5. 按两次ESC进⾏退出;
6. 注释成功。
7. 注意:以下两种需要注释的话,只有⽰例⼆可以成功,⽰例⼀需要在上⾯第⼆步的时候光标需要往左选择,需要到⾏⾸(本⼈亲测-_-..)⽰例⼀:
location ~ /\.ht{
deny all;
}
⽰例⼆:
location ~ /\.ht{
deny all;
}
批量取消注释
1. ⾸先将光标调到要取消注释⾏的⾏头;
2. 按住Ctrl+v进⼊块选模式;
3. 通过按j来调整光标,将所有的注释符号圈中;
4. 取消注释成功。
Linux内核文档:如何写符合kernel-doc规范的注释
![Linux内核文档:如何写符合kernel-doc规范的注释](https://img.taocdn.com/s3/m/20f094c4b04e852458fb770bf78a6529647d3562.png)
Linux内核⽂档:如何写符合kernel-doc规范的注释简介Linux内核使⽤实现把Documentation⽬录下的⽂件转换为⾮常漂亮的⽂档。
⽂档既可以通过 make htmldocs 转换成HTML格式,也可以通过 make pdfdocs 转换为PDF格式。
转换⽣成的⽂档存放于Documentation/output⽬录下。
Linux内核强⼤的⽂档功能,除了直接转换.rst⽂档之外,还能从源码中汲取API说明,结构体说明等信息。
当然要做到这样,源码的注释是有⼀定要求的。
⽽这篇⽂档,就是介绍如何写符合kernel-doc格式要求的注释。
,根据个⼈理解做的翻译,如果有翻译错误的地⽅,请告知。
注释概述符合kernel-doc的注释,都需要从/**开始,其后每⼀⾏内容都以*开头,最后是*/表⽰结束。
例如:/*** This is a sample of comment*/对于函数和类型的注释,必须放在函数和类型之前,以便于别⼈在修改代码的时候,可以顺⼿把注释也改了。
对概述类型的注释,可以放到⽂件顶部的位置。
Linux内核有提供⼀个⼯具⽤于对kernel-doc的格式进⾏检查,例如:$ scripts/kernel-doc -v -none drivers/foo/bar.c当然,在编译的时候,如果添加以下的选项,也会检查⽂档的格式:make W=n函数⽂档规范的格式⽰例如下:/*** function_name() - Brief description of function.* @arg1: Describe the first argument.* @arg2: Describe the second argument.* One can provide multiple line descriptions* for arguments.** A longer description, with more discussion of the function function_name()* that might be useful to those using or modifying it. Begins with an* empty comment line, and may include additional embedded empty* comment lines.** The longer description may have multiple paragraphs.** Context: Describes whether the function can sleep, what locks it takes,* releases, or expects to be held. It can extend over multiple* lines.* Return: Describe the return value of function_name.** The return value description can also have multiple paragraphs, and should* be placed at the end of the comment block.*/函数名后的函数功能简介可以跨越多⾏,以函数参数描述、返回值描述或其他描述结束。
linux中的man命令的详细解释
![linux中的man命令的详细解释](https://img.taocdn.com/s3/m/082e421edf80d4d8d15abe23482fb4daa58d1dca.png)
linux中的man命令的详细解释linux下的man命令是一个帮助命令,掌握这个命令可以让我们更好的学习linux,下面由店铺为大家整理了linux中的man命令的详细解释的相关知识,希望对大家有帮助!一、linux中的man命令的详细解释man命令是Linux下的帮助指令,通过man指令可以查看Linux 中的指令帮助、配置文件帮助和编程帮助等信息。
语法man(选项)(参数)选项-a:在所有的man帮助手册中搜索;-f:等价于whatis指令,显示给定关键字的简短描述信息;-P:指定内容时使用分页程序;-M:指定man手册搜索的路径。
参数数字:指定从哪本man手册中搜索帮助; 关键字:指定要搜索帮助的关键字。
二、linux中的man命令的常用实例分章节查看man的帮助手册:1 标准用户命令可以使用whatis命令是用于查询一个命令执行什么功能,并将查询结果打印到终端上。
例如:[root@nfs-server ~]#whatis cdcd (1p) - change the working directorycd [builtins] (1) - bash built-in commands, see bash(1)#从上文的输出结果我们看到cd命令是bash的内建命令,它的功能是改变当前目录,可以在1和1p的章节中查看它的帮助。
[root@nfs-server ~]#man 1 cd使用上面的命令可以直接查看cd的帮助信息。
[root@nfs-server ~]#man 1p cd因为1p章节是bash的帮助信息,所以在使用"man 1p cd"后,通过在man中输入"/cd"查找相关的信息才能看到cd的帮助信息。
2 系统调用[root@nfs-server]# whatis readread (1p) - read a line from standard inputread (2) - read from a file descriptorread (3p) - read from a fileread [builtins] (1) - bash built-in commands, see bash(1)#从上面可看到,read在1,1p,2,3p中都有内容,下面查看系统调用[root@nfs-server ~]#man 2 read[root@nfs-server ~]#man 2 mount3 库调用[root@nfs-server ~]# man 3 sleep4 特殊文件(设备文件)[root@nfs-server ~]#man 4 tty5 文件格式(配置文件的语法)[root@nfs-server ~]# man 5 passwd6 管理命令[root@nfs-server ~]# man 8 fdisk三、linux中的man命令的使用方法Linux man中的man就是manual的缩写,用来查看系统中自带的各种参考手册,但是手册页分为好几个部分,如下所示:1 Executable programs or shell commands2 System calls (functions provided by the kernel)3 Library calls (functions within program libraries)4 Special files (usually found in /dev)5 File formats and conventions eg /etc/passwd6 Games7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)8 System administration commands (usually only for root)9 Kernel routines [Non standard]----------------------解释一下,1是普通的命令2是系统调用,如open,write之类的(通过这个,至少可以很方便的查到调用这个函数,需要加什么头文件)3是库函数,如printf,fread4是特殊文件,也就是/dev下的各种设备文件5是指文件的格式,比如passwd,就会说明这个文件中各个字段的含义6是给游戏留的,由各个游戏自己定义7是附件还有一些变量,比如向environ这种全局变量在这里就有说明8是系统管理用的命令,这些命令只能由root使用,如ifconfig------------------------------------n新文档,可能要移到更适合的领域。
linux内核完全注释一PPT课件
![linux内核完全注释一PPT课件](https://img.taocdn.com/s3/m/c858b9d6e009581b6bd9eb59.png)
Linux:开放的操作系统
是一个UNIX操作系统的克隆,可以免费使 用,遵循GPL声明,可以自由修改和传播。 Linux包含了人们希望操作系统拥有的所 有功能特性,这些功能包括真正的多任务、 虚拟内存、世界上最快的TCP/IP驱动程序、 共享库和多用户支持。
现在是个人计算机和工作站上的UNIX类操 作系统。它不仅继承了UNIX的特征,而且 在许多方面超过了UNIX。
单内核例子
Linux
微内核优点
内核简单 可移值性好
微内核缺点
开销大
微内核例x简介 Linux的历史与现状
Linux之父
Linus Torvalds(林纳 斯·托瓦兹,1969年12 月28日生 )
毕业与芬兰赫尔辛基大 学计算机科学系,大学 二年级时编写Linux
设备管理
内 核
行在内核模式中
模 式
应用程序与内核模块、
内核模块间的通信是通
过函数调用实现的
硬件
操作系统内核体系结构——微内核
应用程序 设备服务器 文件服务器 IPC、进程管理、内存管理 硬件
用 内核仅包含一些最
户 模
基本功能,运行在
式 内核模式下
其它操作系统功能
内 以服务器的形式提
核 模
批处理操作系统 串行,非交互
单任务单用户操作系统 串行,交互 Dos
多任务单用户操作系统 并行,交互 Windows 98
多任务多用户操作系统 并行,交互,分时共享 Unix、Linux、Windows XP
实时操作系统 并行,响应时间短,容错性 强 嵌入式Linux
供,运行在用户模
式 式下
linux系统术语
![linux系统术语](https://img.taocdn.com/s3/m/47546573a22d7375a417866fb84ae45c3b35c2ea.png)
Linux系统是一个自由和开放源代码的操作系统,基于Unix设计。
以下是Linux 系统中的一些关键术语:
1.内核:内核是操作系统的核心,负责管理系统的硬件和软件资源。
Linux内
核负责调度任务、管理内存、处理硬件中断等。
2.shell:shell是一个命令行界面,用户可以在其中输入命令来与系统交
互。
Linux有多种shell,如bash、zsh、fish等。
3.文件系统:文件系统是用于存储和管理文件和目录的机制。
Linux使用
ext4等文件系统。
4.权限:Linux系统中的每个文件和目录都有相应的权限设置,以确定谁可以
访问和修改它们。
5.用户和组:Linux是多用户系统,用户和组是管理权限的基本单位。
每个用
户都有一个唯一的用户名和密码。
6.服务:服务是Linux上长时间运行的程序,如Apache HTTP服务器或SSH
守护进程。
7.软件包管理:Linux使用包管理器来安装、更新和删除软件。
常见的包管理
器包括APT(Debian和Ubuntu)和yum/dnf(Red Hat系列)。
8.进程:进程是正在运行的程序的实例。
Linux使用init进程作为所有其他
进程的父进程。
9.网络配置:Linux提供了多种工具来配置和管理网络连接,如ifconfig、
ip命令和网络管理器。
10.系统日志:系统日志记录了系统和应用程序的活动,如syslog和dmesg。
linux内核原代码head.s注释
![linux内核原代码head.s注释](https://img.taocdn.com/s3/m/f6b84132bcd126fff7050b42.png)
linux内核原代码head.s部分的注释/** head.s contains the 32-bit startup code.** NOTE!!! Startup happens at absolute address 0x00000000, which is also where * the page directory will exist. The startup code will be overwritten by * the page directory.*/.text.globl _idt,_gdt,_pg_dir_pg_dir:startup_32:movl $0x10,%eax @@ds,es,fs,gs指向内核数据段mov %ax,%dsmov %ax,%esmov %ax,%fsmov %ax,%gslss _stack_start,%esp @@ds送ss esp 指向stack_start (在sched.c定义)@@进入保护模式的堆栈段的第一次变化,很奇怪@@为什么堆栈段也可正向增涨?call setup_idtcall setup_gdtmovl $0x10,%eax # reload all the segment registersmov %ax,%ds # after changing gdt. CS was alreadymov %ax,%es # reloaded in 'setup_gdt' @@ 有reload??mov %ax,%fsmov %ax,%gslss _stack_start,%espxorl %eax,%eax1: incl %eax # check that A20 really IS enabledmovl %eax,0x000000cmpl %eax,0x100000 @@这是怎么测的 0x100000为什么值,@@明白,a20 notenable,0x000000就是0x100000je 1bmovl %cr0,%eax # check math chipandl $0x80000011,%eax # Save PG,ET,PEtestl $0x10,%eaxjne 1f # ET is set - 387 is presentorl $4,%eax # else set emulate bit1: movl %eax,%cr0jmp after_page_tables @@注意,用jmp 不call,不返回/** setup_idt** sets up a idt with 256 entries pointing to* ignore_int, interrupt gates. It then loads* idt. Everything that wants to install itself* in the idt-table may do so themselves. Interrupts* are enabled elsewhere, when we can be relatively* sure everything is ok. This routine will be over-* written by the page tables.*/setup_idt:lea ignore_int,%edxmovl $0x00080000,%eaxmovw %dx,%ax /* selector = 0x0008 = cs */movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ @@ ignore_int 低16-->ax 高16-->edx高字@@ 8e00-->dx 8-->eax高字lea _idt,%edimov $256,%ecxrp_sidt:movl %eax,(%edi)movl %edx,4(%edi)addl $8,%edidec %ecxjne rp_sidtlidt idt_descrret/** setup_gdt** This routines sets up a new gdt and loads it.* Only two entries are currently built, the same* ones that were built in init.s. The routine* is VERY complicated at two whole lines, so this* rather long comment is certainly needed :-).* This routine will beoverwritten by the page tables.*/setup_gdt:lgdt gdt_descrret @@跳到main函数.org 0x1000pg0:.org 0x2000pg1:.org 0x3000pg2: # This is not used yet, but if you# want to expand past 8 Mb, you'll have# to use it..org 0x4000after_page_tables:pushl $0 # These are the parameters to main :-)pushl $0pushl $0pushl $L6 # return address for main, if it decides to.pushl $_mainjmp setup_paging @@再jmpL6:jmp L6 # main should never return here, but# just in case, we know what happens./* This is the default interrupt "handler" :-) */ .align 2ignore_int:incb 0xb8000+160 # put something on the screenmovb $2,0xb8000+161 # so that we know somethingiret # happened/** Setup_paging** This routine sets up paging by setting the page bit * in cr0. The page tables are set up, identity-mapping * the first 8MB. The pager assumes that no illegal* addresses are produced (ie >4Mb on a 4Mb machine).** NOTE! Although all physical memory should be identity* mapped by this routine, only the kernel page functions* use the >1Mb addresses directly. All "normal" functions* use just the lower 1Mb, or the local data space, which* will be mapped to some other place - mm keeps track of* that.** For those with more memory than 8 Mb - tough luck. I've* not got it, why should you :-) The source is here. Change * it. (Seriously - it shouldn't be too difficult. Mostly* change some constants etc. I left it at 8Mb, as my machine * even cannot be extended past that (ok, but it was cheap :-) * I've tried to show which constants to change by having* some kind of marker at them (search for "8Mb"), but I* won't guarantee that's all :-( )*/.align 2setup_paging:movl $1024*3,%ecx @@pg_dir pg_table 清零xorl %eax,%eaxxorl %edi,%edi /* pg_dir is at 0x000 */cld;rep;stoslmovl $pg0+7,_pg_dir /* set present bit/user r/w */movl $pg1+7,_pg_dir+4 /* --------- " " --------- */movl $pg1+4092,%edimovl $0x7ff007,%eax /* 8Mb - 4096 + 7 (r/w user,p) */std1: stosl /* fill pages backwards - more efficient :-) */subl $0x1000,%eaxjge 1b @@ greater or equalxorl %eax,%eax /* pg_dir is at 0x0000 */movl %eax,%cr3 /* cr3 - page directory start */movl %cr0,%eaxorl $0x80000000,%eaxmovl %eax,%cr0 /* set paging (PG) bit */ret /* this also flushes prefetch-queue */@@页目录pg_dir=0 仅两项(8M),@@pg1,pg0页表逆向填充,pg0的首页仍为零@@这样映射,线性地址=物理地址.align 2.word 0idt_descr:.word 256*8-1 # idt contains 256 entries.long _idt.align 2.word 0gdt_descr:.word 256*8-1 # so does gdt (not that that's any @@和前面head.S差一??.long _gdt # magic number, but it works for me :^).align 3_idt: .fill 256,8,0 # idt is uninitialized_gdt: .quad 0x0000000000000000 /* NULL descriptor */.quad 0x00c09a00000007ff /* 8Mb */.quad 0x00c09200000007ff /* 8Mb */.quad 0x0000000000000000 /* TEMPORARY - don't use */.fill 252,8,0 /* space for LDT's and TSS's etc */@@内核逻辑地址(不含段寄存器)=线性地址linux 0.11 内核学习-- head.s## 这段代码被连接到system模块的最前面,这也是它为什么称之为head.s的原因。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
linux整体注释
Linux是一种开源的操作系统,它以其稳定性、安全性和灵活性而受到广泛赞誉。
它的设计初衷是为了提供一个免费且可定制的操作系统,可以运行在各种不同类型的硬件上。
Linux的核心组件是内核,它是操作系统的核心部分,负责管理系统的资源和与硬件交互。
Linux内核具有强大的功能和灵活的架构,可以根据用户的需求进行定制和扩展。
除了内核之外,Linux还包含了许多其他的组件和工具,如Shell、文件系统、驱动程序等。
Shell是与用户交互的界面,它提供了命令行界面和脚本语言,使用户能够以文本方式与系统进行交互。
文件系统负责管理和组织文件和目录,驱动程序则负责与硬件设备进行通信。
Linux有许多不同的发行版,如Ubuntu、Debian、Fedora等。
每个发行版都有自己的特点和目标群体。
例如,Ubuntu注重易用性和用户友好性,而Debian则注重稳定性和安全性。
Linux的优点之一是其开放性和自由性。
作为一种开源软件,任何人都可以查看和修改Linux的源代码。
这使得用户可以根据自己的需求进行定制和优化,而不受商业软件的限制。
另一个优点是Linux的稳定性和安全性。
由于其源代码是公开的,任何人都可以审查和改进代码,从而减少了潜在的漏洞和安全威胁。
此外,Linux也具有良好的稳定性,可以长时间运行而不会出现崩溃或死机的情况。
Linux还支持多用户和多任务,可以同时运行多个程序和服务。
它还具有良好的网络支持和兼容性,可以轻松地连接到互联网并与其他设备进行通信。
Linux是一种强大而灵活的操作系统,它以其开放性、稳定性和安全性而受到广泛欢迎。
无论是个人用户还是企业用户,都可以从Linux的优点中获益,并根据自己的需求进行定制和优化。
通过持续的开发和改进,Linux将继续发展,并成为未来操作系统的重要组成部分。