莱昂氏unix源代码分析导读
文章平均质量分 80
cszhao1980
这个作者很懒,什么都没留下…
展开
-
(莱昂氏unix源代码分析导读-51) 交互式终端
1 DL11/KL11终端有很多种终端可供选择使用,在一台计算机上可能同时连接若干种不同类型的终端。在我们的模型里,使用DL11 / KL 11终端。 一个DL11/KL11终端拥有4个设备寄存器,分为接收和发送两组,可用如下结构表示:8016: struct klregs { 8017: int klrcsr; //接收状态寄存器8018: i原创 2013-09-21 09:05:07 · 4947 阅读 · 4 评论 -
(莱昂氏unix源代码分析导读-37) 文件系统与inode
by cszhao1980前面所讲的各项内容,进程管理也好,中断处理也罢,都静静的工作在幕后,普通用户甚至根本感觉不到他们的存在。但文件系统不同,它工作在前台,用户或多或少都有一定的感性及理性认识——这给我们的读码带来了巨大的好处。在这里我假设大家对unix文件管理有一定的认识,比如,知道文件系统的树状层次结构,知道文件的访问控制,知道绝对路径与相对路径,知道如何将一个原创 2012-12-10 12:34:00 · 4446 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-36) 缓存管理(下)
by cszhao1980理解了上述内容,下面的这些程序就不难理解了。首先是函数brelse(buf bp),该函数将传入的缓存归还到AV队列中,函数采用尾插法,即缓存会插到AV队列的队尾——这样做显然有助于提高“延迟写”技术的效率。莱昂特别指出,brelse没有清理B_DONE标志,这一点非常重要,读完本章后大家就会明白。 接下来是binit()函数,完成初始化:原创 2012-11-19 10:52:49 · 4140 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-35)缓存管理(上)
by cszhao1980系统定义了NBUF个缓存区域,每个514个字节:4720: char buffers[NBUF][514]; 【注】:514个字节稍稍大于一个物理盘块的size,多出的2个byte的用途不明。 而“缓存头”数组buf[NBUF]的每个entry对应一个缓存区域,其b_addr被设置为对应的缓存区的首地址,如:&buffers[1]。对于缓存的使原创 2012-11-12 12:57:39 · 4187 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-34)You are not expected to understand this
By cszhao1980本章将探讨unix v6代码中最微妙的部分,即著名的注释:“ You are not expected to understand this”。 2178: swtch()2179: {2180: static struct proc *p;2181: register i, n;2182: register struc原创 2012-10-31 13:22:51 · 7743 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-33) swap函数
By cszhao1980是了解swap函数的时候了,它有四个参数:(1)blkno:磁盘块号;(2)coreaddr:物理内存block号;(3)count:读写字节数;(4)rdflg:读写标志。 swap函数尽力使用device independent的方法来实现功能:(1)它通过swapdev在块设备表中查表来操控swap设备;(2)启动设备时,通过块设原创 2012-10-15 11:43:02 · 3989 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-32) RK磁盘驱动
by cszhao1980别紧张,RK磁盘是一种非常简单设备——这一点从其代码量中也可以看出。首先,它由一个控制器外加 1~8个devices组成,这8个devices编号为0~7,缓冲头的b_dev的minor号记录的就是该device编号,为简单起见,我们不考虑多于8个device的情况——对RK磁盘来说,b_dev的minor部分就是0~7,而major部分为0。原创 2012-09-24 11:48:34 · 2916 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-31) “缓存头”初探
By cszhao1980struct buf结构,又被称为“缓存头”结构,而buf[NBUF]数组被称为“缓存头”数组。顾名思义,“缓存头”结构应该是用于缓存处理的,事实上,它确实有这个功能——“缓存头”数组的每个entry可与系统的一个缓存区域对应,用于操控一个缓存区域。 4520: struct buf4521: {4522: int b_flags;原创 2012-09-17 15:05:59 · 2530 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-30) device
By cszhao1980我们现在必须放下身段看一看低层的IO操作了,复杂繁琐的外设。 PDP-11/40拥有两种外设:(1) Block device (2) Character device 简单说来,Block device以block来单位操作数据,而character device则以character为单位操作数据。我原创 2012-09-10 12:23:25 · 2656 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-28) swap in/out (中)
by cszhao1980换出时,使用函数xswap(),它有三个参数,前两个参数很容易理解:(1)p——指向进程表项;(2)ff—— free flag,如非0,则free core空间; 但第三个参数就难以琢磨了:(3)os—— old size。是什么意思呢?既然p->p_size记录了进程swap image的size,这个os又是作什么用的。为了理解这原创 2012-08-27 12:28:36 · 2752 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-29) swap in/out (下)
by cszhao1980最后,看一下我们的老朋友sched(),上次看到它还是在系统初启时,#0进程在sched()函数中调用sleep(&runout ,…)睡眠,从而让出cpu,切换至#1进程。 sched()函数是个黑洞,它内部是个死循环,永远也不会退出(除非出错)。也就是说#0进程将陷入在sched()中,而sched()用来进行调度,自此#0进程就蜕变为调度原创 2012-09-03 11:48:42 · 4024 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-27) Swap in/out (上)
By cszhao1980Swap in/out指的是进程在物理内存(core空间)和磁盘交换文件间的双向移动过程,进程在active状态时,其segment必然被swap in内存空间(core空间),而一旦处于非活动状态就有可能被swap out到磁盘交换文件中。换进换出的过程必然涉及到磁盘io——这可看作是比较低层的操作,因此,这部分内容可以分为两部分:高层的模型原创 2012-08-20 12:06:29 · 3244 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-39)inode“资源”的获取和释放
by cszhao1980iget()函数用于获取inode资源,它有2个参数,设备号和inode id。前面说过,通过这两个参数会唯一确定一个inode。简单的说,该函数的作用就是将指定的磁盘inode读入内存inode数组,并Lock该项(即会设置 ILOCK flag),它返回一个指向该inode数组项的指针。 事实上,iget()做的更多一些,它首先检查内存inod原创 2012-12-26 12:55:18 · 4196 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-38)文件物理存放位置与inode
by cszhao1980文件的物理位置指文件存放:(1)哪个设备;(2)该设备的哪些块。 Inode使用i_addr[8]数组来记录文件的物理块号:(1)对“小文件”(占用的块数块),i_addr数组内直接存放文件占用的物理块号; 如文件占用6块,则使用i_addr[0] ~ i_addr[5]存放这6个块号 (2)当文件占用的块数超过8块(此时,原创 2012-12-18 12:32:18 · 4535 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-50)LP11行式打印机
LP11有两个设备寄存器:状态寄存器(lpsr)和数据缓冲寄存器(lpbuf),可通过以下结构进行访问:8812: #define LPADDR 01775148823: struct {8824: int lpsr;8825: int lpbuf;8826: }; (1). LPADDR.lpsr:状态寄存器i. 第15位(最高位):出错标记;原创 2013-08-17 13:16:42 · 3848 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-49) 字符缓冲区
同块设备一样,对字符设备的输入输出也是通过缓冲区来进行的。使用缓冲区有个额外的好处,即以缓冲区为界,函数可分为高低两个层次。低层函数负责与实际设备交互,而高层函数只与缓冲区打交道,只对缓冲区存取数据,这样可以蔽掉掉底层的许多细节。 对于字符缓冲区,有两个最重要结构,即cblock和clist。前者是缓冲区本身,后者则用作字符链表(队列)的头结点。莱昂在第23章中详细介绍了这两个原创 2013-08-02 12:28:14 · 3885 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-47) exec
by cszhao1980现在,我们已经储备了足够的知识,该吹响向EXEC sys call冲锋的号角了。exec是系统中最重要也是最复杂的系统调用之一,它的作用是执行指定的“可执行文件”。一般说来,exec与fork配合使用,fork生成一个新进程,而exec是新进程执行其应该执行的代码。 莱昂对exec有着比较详细的介绍,但很不幸,这些代码理解起来仍然困难重重。所以,我要在原创 2013-06-30 08:54:28 · 4959 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-48) 字符设备
我们终于到达了本书的最后一章,它涉及的是慢速、面向字符外部设备的输入和输出。同块设备一样,unix v6使用一个“设备switch” struct来进行设备操控。原创 2013-07-15 12:42:34 · 3886 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-46)权限、管道
by cszhao1980 1. 文件与权限控制进程u结构中,身份相关的信息有:0420: char u_uid; /* effective user id */0421: char u_gid; /* effective group id */0422: char u_ruid; /* real user id */0423: char u_rgid; /* rea原创 2013-06-15 21:10:21 · 3979 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-45) 文件与“资源”
by cszhao1980我们已经知道文件会占用很多资源,如磁盘inode资源、盘块资源,访问时还要占用inode数组资源,等等。 除此之外,unix v6还使用file数组来记录整个系统中被open开的文件,file数组的定义如下:5507: struct file5508: {5509: char f_flag;5510: char f_co原创 2013-05-29 19:33:28 · 4059 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-44) 文件系统资源
by cszhao1980一个设备被mount进系统后,就被称为一个文件系统。它有两类资源:(1) 磁盘inode资源;(2) 普通盘块资源。1. 磁盘inode资源对于inode资源,unix v6采用了一种很简单的管理方法。即在超级块中维护一个free inode资源数组(max 100 entry),存放可用的inode资源(inode原创 2013-05-05 08:20:34 · 3996 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-42) 硬链接
by cszhao1980熟悉unix/linux的同学都听说过硬链接的概念,老实说,在阅读源码之前,对硬链接的理解总是模模糊糊的。现在,我们已经了解了inode、目录,是时候对硬链接有个清楚的了解了。 我们知道,新建一个文件时,需要申请很多资源,如:(1)申请磁盘盘块用于写文件的内容;(2)申请inode资源,存放文件inode;(3)在父目录文件中添加一目录项,原创 2013-03-25 11:15:27 · 4105 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-43) 文件系统的mount
By cszhao1980当一个设备被mount进系统,就会在“mount表”中占据一个表项,mount表的定义如下:0272: struct mount0273: {0274: int m_dev /* device mounted */0275: int *m_bufp; /* pointer to superblock */0276:原创 2013-04-02 09:13:05 · 3820 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-41)文件系统树状结构的形成
By cszhao1980我们现在对inode有了一定的了解,正如前面所说,inode记录的信息比较靠近文件的物理存储。那末,文件系统的树状结构是如何实现的呢? 答案就是“目录”。首先需要强调的是,目录也是一种文件,它也拥有与普通文件相同的inode结构。所不同的是其文件内容——逻辑上,我们可以把目录文件的内容看作一个“目录项数组”,它由若干“目录项”构成,一个目录原创 2013-02-25 12:11:17 · 4479 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-40)inode“指向文件的内容”的读写
by cszhao1980前面已经说过,inode指向文件的内容是通过i_addr[]数组来组织和记录的。本章讨论一下文件内容的读写。在进行文件读写时,使用了进程u空间的若干变量,先介绍如下: 0418: char u_segflg; /* flag for IO; user or kernel space */0425:原创 2013-01-18 13:33:08 · 3871 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-26) trace
by:cszhao1980trace是unix提供的一种是父进程可以跟踪子进程进展的手段,子进程被跟踪时,当子进程收到signal后,会进入“暂停(SSTOP)”状态,使父进程有机会进行干预。子进程的暂停是在issig()函数中实现的: 3997: if(n = p->p_sig) {3998: if (p->p_flag&STRC) { /进程处原创 2012-08-14 12:03:43 · 2435 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-24)signal(上)
by cszhao1980signal更确切的称呼应该是soft interruption,顾名思义,就是一种能够通过软件手段达到类似interruption目的的方法。 Unix最多支持NSIG(20)种软中断,进程的u中有u.signal[NSIG]数组,记录每种软中断的处理方法。u_signal〔n〕的值当#n中断发生时原创 2012-07-30 12:54:12 · 2582 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-6) stack使用和进程的分段
1.Stack使用:PDP11使用倒置的栈,即栈底在高地址,栈向低地址生长,如下图所示:(1) 压栈示例: MOV R1,–(SP) 先移动SP,再放置R1(2) POP示例: MOV (SP)+,R1 先取栈内值,再移动栈指针释放该地址。 参数压栈规则:(1)原创 2012-05-21 11:56:17 · 4768 阅读 · 3 评论 -
(莱昂氏unix源代码分析导读-1) 引子
那一年不知怎样,此书忽在世间出现,天下学武之人自然个个都想得到,大家你抢我夺,一塌里胡涂。 一直以来,操作系统都是程序员心中的圣殿,每个程序员都想登堂入室,掌握其中的奥秘。但是,在上世纪六七十年代,对普通程序员来说,这只能是个梦想。因为在那时,操作系统不啻为一个蛮荒巨兽,它往往由数十万乃至数百万行的汇编语句组成,对普通程序员而言,根本无法对其进行分析和理解。 Unix的出现改变了这原创 2012-05-14 19:39:04 · 10918 阅读 · 4 评论 -
(莱昂氏unix源代码分析导读-4)PDP11/40系统简介(下)
1 Page Register 分为Address Register和Description Register,在“存管系统”起效后使用。Kernel和User态各有8组Register,分别完成8页的“物理---逻辑”地址映射。 比如,代码中对Address Register有如下的声明: Kernel原创 2012-05-17 12:01:45 · 5238 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-3)PDP11/40系统简介(中)
1。 通用寄存器。共有8个通用寄存器,r0 ~ r7 R5:环境寄存器。 R6: 又名sp,即栈寄存器 —— kernel/usr各有一个 R7: 又名PC,即指令指针寄存器 2 PS Register即processor status register,该寄存器的使用非常频繁,其结构如下所示: (1) codition cod原创 2012-05-16 12:03:20 · 5845 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-2) PDP11/40系统简介(上)
独臂人道:“不错,你好好瞧着。你那本拳经刀谱,前面缺了两页,所以你总是说瞧不懂。那缺了的两页,就在这人身上 1. 地址管理PDP11最大的特点是其UNIBUS系统,CPU对所有设备的访问都通过单一总线来完成。因此,所有设备都具有统一的编址规则。也就是说,所有设备,包括Memory、Register、外设、Device Register等都具有统一的地址。外设、Device Regi原创 2012-05-15 10:26:24 · 9351 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-15) 系统初启(8)
进程user态下的分段 User态中将进程空间分为text、data、stack segment三部分。 estabur(nt, nd, ns,sep)根据各个segment的大小,为各段分配page,参数如下:(1) nt—— text segment的长度(block)(2) nd—— data segment的长度(block)(3) ns—— stack seg原创 2012-06-01 12:05:28 · 4096 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-14)系统初启(7)
#1进程 现在,是#1进程的天下了。回到main函数:1627 if(newproc()) { /返回值为1,要执行以下的语句1628 expand(USIZE+1); /扩展进程私有空间,增大1个block 1629 estabur(0, 1, 0, 0); 1630原创 2012-05-31 12:12:54 · 4005 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-13)系统初启(6)
#0进程的switch 我们已经了解了进程的switch原理,接下来,我们继续跟踪#0进程,看发生了什么。 1940: sched()1941: {……1951: goto loop;……1957: loop:1958: spl6();原创 2012-05-30 12:40:25 · 4628 阅读 · 2 评论 -
(莱昂氏unix源代码分析导读-12)系统初启(5)
进程switch现在让我们考虑一个问题,如何确定当前Active的进程是哪个呢?要知道,进程并不独享某段代码,我们不可能通过当前执行的代码来确定哪个进程处于Active状态。 显然,应该通过进程私有的东西来确定——而进程所私有的只有一样,即Kernel page 6(即ppda所在的Page)。我们通过KISA6来确定Active进程,即KISA6指向哪个进程的“私有空间”,则原创 2012-05-29 12:21:20 · 4541 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-11)系统初启(4)
本章讨论进程复制,继续Main函数。 1625 */16261627 if(newproc()) { …… 现在看newproc的代码。1826 newproc()1827 { ......1840 retry: 1841 mpid++;原创 2012-05-28 12:16:54 · 4480 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-7) c语言若干问题
Unix的开创者之一丹尼斯-里奇,同时也是C语言的老祖宗。他把c语言引入了unix,从而开辟了一个崭新的时代。C语言和unix的关系,真真称的上是鱼水情深,密不可分。毫不夸张的说,是c语言成就了unix,而同时也是unix成就了c语言。 大家对这门语言自然是十分熟悉,但在这里我还是要多说几句。 首先,我们所分析的代码写于70年代初中期,其时c语言也刚刚成型,其语法与现在的c原创 2012-05-22 11:57:11 · 4961 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-18) 再谈中断与陷入
从产生原因看,中断和陷入也有巨大的差别。 硬件中断由外部事件造成,属于异步事件,往往与当前进程毫无关系;陷入则不同,它常常都是同步的(如除0错),并与当前进程上下文相关。 除此之外,陷入还用来实现系统调用——内核为user进程提供了大量的服务,这些服务就是通过系统调用来访问的。PDP11提供了trap指令来使user进程进入内核,进行系统调用。 由于系统调用的存在,原创 2012-06-11 12:00:03 · 4156 阅读 · 0 评论 -
(莱昂氏unix源代码分析导读-17)系统初启(10)
小结本章的内容到此结束。由于我们跳过了一些专题,启动代码中仍有一些未解之谜,但它的神秘面纱已经揭开,这是一个好的开始。 最后,给出fuibyte(0)的分析结果:0814 _fuibyte: 0815 _fubyte:0816 mov 2(sp),r1 /参数(输入地址)--->r10817 bic $1,r1原创 2012-06-05 11:59:51 · 3850 阅读 · 0 评论