登陆论坛
|
论坛注册
|
加入收藏
|
设为首页
|
RSS
首页
Linux频道
软件下载
开发语言
技术论坛
嵌入式频道
|
数据库开发
|
WEB开发
|
软件开发
|
嵌入应用
|
内核研究
|
SHELL
|
输入您的搜索字词
提交搜索表单
您当前的位置:
首页
>
Linux频道
>
Linux开发区
>
内核研究
Linux 2.4 内核说明文档(进程与中断管理篇)
时间:2006-07-07 21:11:57 来源:
chinaunix
作者:xuediao
本文档是《Linux2.4 内核说明文档》中的第二部分。以下是整个文档大致目录:
N9ULinux联盟
1,启动 ([url=http://bbs.chinaunix.net/forum/viewtopic.php?t=557946]http://bbs.chinaunix.net/forum/viewtopic.php?t=557946 )
N9ULinux联盟
2,进程和中断管理
N9ULinux联盟
3,虚拟文件系统
N9ULinux联盟
4,Linux 页缓冲
N9ULinux联盟
5,IPC机制
N9ULinux联盟
N9ULinux联盟
本篇文档的目录为:
N9ULinux联盟
2.1. Tack结构和进程表
N9ULinux联盟
2.2. 创建和中止任务与内核线程
N9ULinux联盟
2.3. 调度程序
N9ULinux联盟
2.4. Linux执行链表
N9ULinux联盟
2.5. 等待队列
N9ULinux联盟
2.6. 内核时钟
N9ULinux联盟
2.7. Bottom Halves
N9ULinux联盟
2.8. 任务队列
N9ULinux联盟
2.9. I386体系中系统调用实现
N9ULinux联盟
2.10. 原子操作
N9ULinux联盟
2.11. 旋转锁、读写旋转锁和Big-Reader旋转锁
N9ULinux联盟
2.12. 信号灯和读写信号灯
N9ULinux联盟
2.13. 装载模块的内核支持
N9ULinux联盟
N9ULinux联盟
一下是正文:
N9ULinux联盟
2. 进程和中断管理
N9ULinux联盟
N9ULinux联盟
2.1. Tack结构和进程表
N9ULinux联盟
linux下的每个进程都是动态分配一个task_struct结构,整个系统可以创建的最大进程数仅由当前可用物理内存总数限制,并且等于(见kernel/fork.c:fork_init()函数):
N9ULinux联盟
N9ULinux联盟
/*
N9ULinux联盟
* The default maximum number of threads is set to a safe
N9ULinux联盟
* value: the thread structures can take up at most half
N9ULinux联盟
* of memory.
N9ULinux联盟
*/
N9ULinux联盟
max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 2;
N9ULinux联盟
N9ULinux联盟
这个式子在IA32体系结构上主要意味着最大数为物理内存页数/4,例如:在一个512M内存机器上你可以创建32K线程。这对于旧版本(2.2或者更老)内核的4K限制是一个可观的改进,而且这可以在运行时使用系统调用sysctl(2)修改KERN_MAX_THREADS,或者简单使用procfs系统接口来调整。
N9ULinux联盟
N9ULinux联盟
# cat /proc/sys/kernel/threads.max
N9ULinux联盟
32764
N9ULinux联盟
# echo 100000 >; /proc/sys/kernel/threads.max
N9ULinux联盟
# cat /proc/sys/kernel/threads.max
N9ULinux联盟
100000
N9ULinux联盟
# gdb .q vmlinux /proc/kcore
N9ULinux联盟
Core was generated by `BOOT_IMAGE=240ac18 ro root=306 video=matrox:vesa:0x118'.
N9ULinux联盟
#0 0x0 in ?? ()
N9ULinux联盟
(gdb) p max_threads
N9ULinux联盟
$1 = 100000
N9ULinux联盟
N9ULinux联盟
Linux系统上进程的关联表现为一个以下两个方式链接的task_struct结构的集合:
N9ULinux联盟
1) 以pid为键值的hash表。
N9ULinux联盟
2) 通过p->;next_task和p->;prev_task指针连接的双向链表。
N9ULinux联盟
这个hash表名为pidhash,并在include/linux/sched.h中定义:
N9ULinux联盟
N9ULinux联盟
/* PID hashing. (shouldnt this be dynamic?) */
N9ULinux联盟
#define PIDHASH_SZ (4096 >;>; 2)
N9ULinux联盟
extern struct task_struct *pidhash[PIDHASH_SZ];
N9ULinux联盟
#define pid_hashfn(x) ((((x) >;>; 8) ^ (x)) & (PIDHASH_SZ . 1))
N9ULinux联盟
N9ULinux联盟
所有的任务以他们的pid为键值存放到hash表中,并假定均匀地从(0 to PID_MAX-1)分布。这个hash表用来通过指定的pid快速的找到task结构,搜索函数find_task_pid()定义在include/linux/sched.h中:
N9ULinux联盟
N9ULinux联盟
static inline struct task_struct *find_task_by_pid(int pid)
N9ULinux联盟
{
N9ULinux联盟
struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
N9ULinux联盟
for(p = *htable; p && p.>;pid != pid; p = p.>;pidhash_next)
N9ULinux联盟
;
N9ULinux联盟
return p;
N9ULinux联盟
}
N9ULinux联盟
N9ULinux联盟
在每个hash链上的所有任务都通过p->;pidhash_next和p->;pidhash_pprev连接起来,这在hash_pid函数和unhash_pid函数将指定进程插入hash表或者移出hash表时使用。所有的操作都受到tasklist_lock写同步锁保护。
N9ULinux联盟
而双向链表则为系统遍历所有的任务提供了方便,这个操作由定义在include/linux/sched.h中的for_each_tack()宏来实现。
N9ULinux联盟
N9ULinux联盟
#define for_each_task(p) \
N9ULinux联盟
for (p = &init_task ; (p = p.>;next_task) != &init_task ; )
N9ULinux联盟
N9ULinux联盟
for_each_task()函数的使用者必须使用tasklist_lock读同步锁。注意for_each_task()函数采用init_task标识链表的起点,这样才是安全的,因为空任务(pid = 0) 是不在链表里的。进程hash表和进程链表的修改操作,特别是fork函数,exit函数和ptrace函数,必须调用tasklist_lock写同步锁。更有趣的是,所有的写操作还必须屏蔽当前CPU的中断,这个原因是显而易见的:send_sigio函数遍历了进程表,这样需要调用tasklist_lock读同步锁,并且该函数是kill_fasync函数在中断环境下调用的。
N9ULinux联盟
现在我们已经知道task_struct结构是怎样链接到一起的,现在让我们分析一下task_struct结构的成员。这些成员是UNIX系统的proc结构和user结构松散组合到一起的。
N9ULinux联盟
其他UNIX版本总是将进程状态信息作为单独一部分常驻内存,其他部分则作为进程运行时所需信息,如此简陋的设计仅仅因为内存时非常宝贵的资源。现代操作系统(如Linux或者FreeBSD)并不做如此区分,而是在内核常驻内存的数据结构中维护进程状态。
N9ULinux联盟
include/linux/sched.h中定义了task_struct结构,并且通常大写为1680字节,状态宏也定义同一个头文件中。
N9ULinux联盟
N9ULinux联盟
volatile long state; /* .1 unrunnable, 0 runnable, >;0 stopped */
N9ULinux联盟
#define TASK_RUNNING 0
N9ULinux联盟
#define TASK_INTERRUPTIBLE 1
N9ULinux联盟
#define TASK_UNINTERRUPTIBLE 2
N9ULinux联盟
#define TASK_ZOMBIE 4
N9ULinux联盟
#define TASK_STOPPED 8
N9ULinux联盟
#define TASK_EXCLUSIVE 32
N9ULinux联盟
N9ULinux联盟
为什么TASK_EXCLUSIVE宏定义为32而不是16呢?这是由于16被TASK_SWAPPING使用了,并且后来在移出TASK_SWAPPING时没有把TASK_EXCLUSIVE的值上调。
N9ULinux联盟
可变量p->;state的定义意味着它自身可以被中断处理者异步修改。
N9ULinux联盟
1) TASK_RUNNING:含义是假定任务已经处于运行队列中。至于不是已经处于运行队列的原因是由于将一个任务标识为TASK_RUNNING和将该任务移动到运行队列不是一个原子操作。从运行队列角度考虑,操作时需要保持runqueue_lock读同步锁。如果这样操作,你将发现在运行队列的每个任务都处于TASK_RUNNING状态。然后,反过来却不一定。同样地,驱动程序可以标识他们自身状态为TASK_INTERRUPTIBLE,然后调用schedule()函数,这个函数将从运行队列移出它自己(除非当时有一个导致它滞留在运行队列的未处理信号)。
N9ULinux联盟
2) TASK_INTERRUPTIBLE:含义是任务处于休眠状态但可以通过一个信号或者休眠中止时钟唤醒。
N9ULinux联盟
3) TASK_UNINTERRUPTIBLE:含义类似于TASK_INTERRUPTIBL,但任务不能被唤醒。
N9ULinux联盟
4) TASK_ZOMBIE:含义是任务已经被中止但它的状态还没被父进程获取。
N9ULinux联盟
5) TASK_STOPPED:含义是由于任务控制信号或者ptrace系统调用,任务已经被停止。
N9ULinux联盟
6) TASK_EXCLUSIVE:含义是这不是一个单独状态,但能够与TASK_INTERRUPTIBLE或者TASK_UNINTERRUPTIBLE状态并存(OR操作)。这意味着当任务与其他在等待队列休眠时,它可以单独被唤醒而不需要唤醒整个等待队列的任务。
N9ULinux联盟
任务标记包含了关于非互相排斥的进程状态信息。
N9ULinux联盟
N9ULinux联盟
unsigned long flags; /* per process flags, defined below */
N9ULinux联盟
/*
N9ULinux联盟
* Per process flags
N9ULinux联盟
*/
N9ULinux联盟
#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */
N9ULinux联盟
/* Not implemented yet, only for 486*/
N9ULinux联盟
#define PF_STARTING 0x00000002 /* being created */
N9ULinux联盟
#define PF_EXITING 0x00000004 /* getting shut down */
N9ULinux联盟
#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */
N9ULinux联盟
#define PF_SUPERPRIV 0x00000100 /* used super.user privileges */
N9ULinux联盟
#define PF_DUMPCORE 0x00000200 /* dumped core */
N9ULinux联盟
#define PF_SIGNALED 0x00000400 /* killed by a signal */
N9ULinux联盟
#define PF_MEMALLOC 0x00000800 /* Allocating memory */
N9ULinux联盟
#define PF_VFORK 0x00001000 /* Wake up parent in mm_release */
N9ULinux联盟
#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */
N9ULinux联盟
N9ULinux联盟
p->;has_cpu, p->;processor, p->;counter, p->;priority, p->;policy and p->;rt_priority字段和调度程序关联,并将在后面描述。
N9ULinux联盟
p->;mm 和p->;active_mm字段分别指向mm_struct结构描述的进程地址空间和有效地址空间(如果这个进程不是内核进程的话)。这使得当任务被调度离开时TLB能够在地址空间自由切换。所以,如果当前正在执行内核任务(没有p->;mm),则它的next->;active_mm将被设置为已经被调度离开的任务的prev->;active_mm,如果pre-mm != NULL,则这个地址将和prev->;mm相同。如果CLONE_VM标识传递到了clone系统调用或者依靠vfork系统调用,则地址空间可以在任务之间共享。
N9ULinux联盟
p->;exec_domain和p->;personality字段与任务的特性相关,也就是为了模仿UNIX特性的唯一系统调用。
N9ULinux联盟
p->;fs字段包含了文件系统信息,在linux下有三个方面的含义:
N9ULinux联盟
1) root目录实体结构和挂载点;
N9ULinux联盟
2) 预备的root目录实体和挂载点;
N9ULinux联盟
3) 当前工作目录实体和挂载点;
N9ULinux联盟
这个结构同样包含了一个引用计数,因为当进行带CLONE_FS标识的clone系统调用时,它是共享的。
N9ULinux联盟
p->;files字段包含了文件句柄表,这在进行带CLONE_FILES标识clone系统调用时也是多任务共享的。
N9ULinux联盟
p->;sig字段包含了信号处理函数入口,以CLONE_SIGHAND参数执行clone操作后页可以在进程间共享。
来顶一下
返回首页
发表评论
共有
条评论
用户名:
密码:
验证码:
匿名发表
相关文章
vmware下重新编译内核必选选项
Linux 2.4 内核说明文档(引导篇
Linux2.6内核驱动移植
一种解读linux内核源码的入门方法
编译内核操作流程
内核管理概述
入门:Linux 2.6 内核的嵌入式系统
几个重要的RedHat Linux内核文件
debian内核防毒AntiVir安装
Linux 核心--12.Linux内核机制
栏目更新
栏目热门
站内搜索:
Linux频道
下载频道
图库
商品
嵌入式频道
高级搜索
网站首页
|
关于我们
|
服务条款
|
广告服务
|
联系我们
|
网站大全
|
免责声明
|
返回顶部
Copyright © 2007-2008 xxlinux.com, All rights reserved.
Powered by linux联盟
京ICP备05012402号