Chinaunix首页 | 论坛 | 博客
  • 博客访问: 731908
  • 博文数量: 741
  • 博客积分: 6000
  • 博客等级: 准将
  • 技术积分: 4825
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-18 11:18
文章分类

全部博文(741)

文章存档

2011年(1)

2008年(740)

我的朋友

分类:

2008-09-18 11:24:23

前些天读“linux内核源代码情景分析”(毛德操),觉得开始写得还不错,后面的讲解过于细节,让人不能从整体上有个把握(看了几本国内写的内核的书,好象都是给几段编码,加点注解)。我感觉,即然内核也是一个软件,就应该以软件工程的方法去理解它。用软件工程设计方法当然是:需求,总体设计,详细设计,编码等等。我想老毛的书基本在编码讲解层次上,让人不能有一种宏观把握的清晰思路。我感觉要读懂源码,应该首先从总体上理解,即弄明白设计理念,其次才是具体的编码理解。所以我这两天转向从总体上把握它。现在在读
<深入理解linux内核>,它写得很好,我已读了中断异常,时钟中断,进程几章,它把中断异常,时钟中断设计的思路讲得非常清楚,我推荐大家读一下此书。
我有个问题还没想太清楚,请大家指点:
一个进程要进入TASK_INTERRUPTIBLE OR TASK_UNINTERRUPTIBLE状态,这应该具备什么条件,及如何唤醒(能不能醒就看进程能不能被放入就绪队列)?
这个问题我想了又想,觉得:
进程要睡觉有自愿和被迫两种
自愿,主要是调sleep_on()等,他们的唤醒靠挂在定时器上的函数,此函数会把相应的睡眠进程放入就绪队列,从而唤醒了进程。
被迫方式主要是因为等待事件。等待事件我理解为等待某信号量可用,当内核函数帮进程检查某信号量是否可用时,若发现不可用,内核函数就会把进程挂到等待队列中(信号量的队列中,好象挂到信号量的队列中便没必要挂到等待队列中,只要不让进程挂到运行队列便可),不让进程被调度。当某进程释放信号量指示的资源或发出某事件时,它会调用类似的PV操作的V操作函数,此V操作函数会把等待进程放入就绪队列,从而唤醒了进程。

这便是我对进程睡觉和被唤醒的理解,不知正确于否?欢迎发表你读内核的感受。

相互交流,共同进步      
--------------------next---------------------
首先声明一下,本人一不小心把贴子发错位置了,放到了“内核源代码学习”,所以我在这里又放了一份。
所以你若回贴,请回到内核日记里。很是抱歉。

今日日记:
我想再问一个问题:
进入TASK_INT..,TASK_UNINT..的是不是都必须处在某个等待队列中?
我的理解是:有的进程进入睡眠态根本不挂入等待队列,
理由是:比如定时睡眠(内核函数为:sleep_on_timeout(),
interruptible_sleep_on_timeout()),这些函数会为进程申请一个动态定时器,然后把定时器的data域设成进程的PID,这样当定时器到时,便会把进程唤醒,这就没有用到等待队列。
不知理解正确于否,欢迎指正。

今天看了信号量机制和内存管理(buddy算法和slab分配器,还有点问题,不过等看完再提),还有就是跟踪系统调用。
我想就跟踪再提个问题:
硬件对跟踪提供了两种机制:eflags的IF标志,调试寄存器组
linux在进程控制表中提供:PF_TRACESYS标志用来中断系统调用
(不知还有没有别的方式?)
当A进程被B进程跟踪时,B则为A的父进程(这点应该没有问题吧),若此时A遇上断点被中断,它会进入TASK_STOPPED状态,B会收到一个SIGCHLD信号,从而被唤醒当B运行时,它会检查A的状态,无外乎是看 B的硬件上下文,B的某内存数据,或B的进程控制表中能体现的所有信息。(还会不会看别的什么?)
我现在想问:B通过系统调用要求看这些信息时,内核如何服务?
我把我的想法写出,欢迎补充指正:
1。B要看A的寄存器和进程控制表中能体现的所有信息,内核只需从进程控制表中提取便可。
2。B要看内存某内存数据,则应该给系统调用传地址参数,内核就必须想法找到
A的地址空间中找到此数据,如何找呢?(这是问题的关键) 我想内核会利用A的页全局目录,采用计算方法找此数据的物理地址,然后利用内核的内存的固定映射方法得到在A空间的线性地址(此地址>3G),然后就可以访问到此数据。

不知我的理解是否正确?      
--------------------next---------------------
2003.04.19读核日记:

今天看内存管理,深感知识面不够!
在内存管理的3个主要数据结构:BUDDY算法,SLAB分配器,vm_area分块,其中slab最难理解。
现在有一点不太明白,提出来请大家指点:

kmalloc,vmalloc,malloc有什么区别?

内核通过buddy对大块物理内存进行管理,通过slab分配器对零碎的数据结构提供
分配服务,这样内核所需的内存无论大块小块都有函数可用了。
那用户进程的内存空间如何管理?内核通过vm_area_struct技术实现用户线性空间大块内存分配,比如:代码区,数据区,堆区,栈区。我现在想问,当进程需要小块内存时,由谁来管理?我知道,一般用户通过malloc来分配零碎的内存。
但malloc通过什么方法来对得到零碎内存,是通过系统调用,还是不用系统调用?我查了系统调用,好象没有相应的系统调用,我又没有发现内核为用户空间的零碎内存管理提供任何算法。所以我怀疑malloc没有用系统调用,可不用系统调用它又用什么方法来实现呢?我想了以想,觉得若malloc不用系统调用,则它必须自己来管理,即它必须自己建立一个管理数据结构,那又用什么数据结构呢,最简单的方法就是用链把已分配的零碎块串起来,复杂一点的话也可仿slab来管理。
不知大家谁对malloc的分配机理清楚?若大家谁有C库源码,不妨共享一下。

对了,还有一个问题?
对库如何实现反汇编?      
--------------------next---------------------
2003.04.20读核日记--未来LINUX架构随想

今日浏览了一下VFS,对它的设计思想很是佩服。它实现的思路我的理解就如
PCI插槽,插上不同的独立设计的具体文件系统,便可扩展功能。
所以与其说VFS是一个通用文件系统的接口,不如说它是一个技术规范。
通过这种规范,可实现不同的软件的无缝对接。
再联想到POSIX,不也是OS设计的规范吗,所以我想,会不会有一天能把linux
的各部分之间也设计能用规范相联,就如同组装PC机一样。不过,令人心慰的是
VFS已经实现了文件系统与具体文件系统的规范。我想下一步应该把内存管理也设计成规范,linux其它部分只通过标准的函数接口就能完成从物理内存分配,回收
,进程空间的管理,还有缓冲的管理。说到缓冲的管理,我想linux内核的缓冲主要有两大类:一是固定对象的分配回收的缓冲(或叫缓冲池),如通过SLAB进行的小对象分配机制。二是高速缓冲,如磁盘块的预读管理,页面的老化等。应该把这两种缓冲管理也标准化。 说不定到那时,我们也可象设计具体文件系统那样把内存管理单独设计成一个模块,然后不用重编内核,就可以把原内存管理模块通过如INS_MM_MODE的函数换成自己设计的内存管理模块。我都想过了,在替换时,要实现旧新工作的交接,即要把旧模块的数据记录转换给新模块,以使新模块重绘内核内存图景。我们的目标:LINUX要傻瓜式组装,将有许多内存管理,进程管理,文件系统的插件可选,以适应自己具体情况的需要。

 不过目前的目标:好好读核,不要空谈。(这两天学习有点冒进的苗头,书光想住后翻)
 希望大家也在此谈谈你们的读核经验,以让象我这样的棒槌少走点弯路。      
--------------------next---------------------
今日读BUDDY内存分配算法,算法确实很不错,但LINUX在初始化BUDDY算法的数据结构时很低效。
我先打个比喻:给你一个大碗,里面装满了大米,现在让你大米转移到
另一个碗里,你是把米从一个碗直接倒到另一个碗里,还是把米一粒一粒从一个碗放到另一个碗里?答案是明确的,直接倒。
而linux在初始化BUDDY算法的数据结构时却选择了类似把米从一个碗一粒一粒放到另一个碗里方法。
好了,看看系统是如何初始化BUDDY算法的数据结构的。
BUDDY在回收页面时一般用free_pages(),free_page(),它们都要实现伙伴的合并。而且最多9-order次合并。

在mem_init()中,通过对所有的动态内存进行逐页扫描,并调用free_page()来把空页一页一页的插入BUDDY中。

事实上,动态内存就那么几大块,所以完全可以用一个递归函数用很少的
次数就可完成工作。
我写了一个:
buddy_init( start_addr,end_addr, order)
//start_addr,end_addr为要释放的内存块首尾,order为要插入的BUDDY槽号
{unsigned long mask=(~0ul)<
page *  start,end;  //中间以order为边界的大块的首尾地址

if(order==0)
{free_page(start_addr); return; }  //递归出口,即只有一页要求释放

//求出start,end;
start=(start_addr+(1< end= end_addr&mask;

for(tmp=start,tmp {free_pages(tmp,order); //中间以order为边界的大块的释放
}

if(start_addr!=start) //若相等,则说明没有左零头,不用再递归
buddy_init(start_addr,start,order-1);
if(end_addr!=end) //若相等,则说明没有右零头,不用再递归
buddy_init(end,end_addr,order-1);




函数写的不严密,但其思想是尽量用free_pages()来大块大块的插入,
因为这样一次最多可释放512页,比一页一页效率高多了。      
--------------------next---------------------

阅读(192) | 评论(0) | 转发(0) |
0

上一篇:欢迎阅读我的文章

下一篇:2

给主人留下些什么吧!~~