《第二章》进程管理和调度
主流的Linux内核不支持硬实时,但一些修改版本如RTLinux、Xenomai、RATI。在这些修改方案中,Linux内核作为独立进程运行,实时的工作在内核外部完成,只有当没有实时操作的时候,内核才会运行。
2.5内核中引入了O(1)的调度算法,2.6.23时引入完全公平调度器(CFS)。
命名空间
命名空间建立了系统的不同视图,此前的每一项全局资源都必须包装到容器数据结构中,只有资源和包含该资源的命名空间组成的二元组仍然是全局唯一的。
新的命名空间的创建:
1. fork或者clone时,可以设定是与父进程共享命名空间还是创建新的命名空间;
2. unshare系统调用将进程的某些部分从父进程分离出来,其中包括命名空间。
命名空间的实现:
1.每个子系统的命名空间结构;
2.将给定进程关联到所属各个命名空间的机制。
每个子系统的命名空间结构
struct nsproxy {
atomic_t count;
struct uts_namespace *uts_ns;
struct ipc_namespace *ipc_ns;
struct mnt_namespace *mnt_ns;
struct pid_namespace *pid_ns;
struct user_namespace *user_ns;
struct net *net_ns;
};
UTS命名空间
struct uts_namespace {
struct kref kref;
struct new_utsname name;
};
struct new_utsname {
char sysname[65];
char nodename[65];
char release[65];
char version[65];
char machine[65];
char domainname[65];
};
用户命名空间
struct user_namespace {
struct kref kref;
struct hlist_head uidhash_table[UIDHASH_SZ];
struct user_struct *root_user;
};
pid命名空间
某些进程具有多个pid(凡是可以看见该进程的命名空间都得分一个pid给它),数据结构要反映出局部pid和全局pid。全局pid指在内核本身和初始命名空间(init进程所在的命名空间)唯一的pid,局部pid指特定命名空间中中该进程的pid。task_struct中保存的pid和tgid是全局pid和线程组ID。
struct pid_namespace {
...
//相当于全局的init进程,用来对孤儿进程调用wait4
struct task_struct *child_reaper;
...
intlevel;//该命名空间的层次
struct pid_namespace *parent;//父命名空间
};
pid的管理围绕两个数据结构展开---struct upid,struct pid。
struct upid { //对特定命名空间课件的pid信息
int nr; // ID数值
struct pid_namespace *ns; //该ID所属的命名空间
struct hlist_node pid_chain; //所有的upid放在散列表pid_chain中。
};
struct pid { //内核对pid的内部表示
atomic_t count;
/* 使用该pid的进程列表的数组。*/
struct hlist_head tasks[PIDTYPE_MAX];
intlevel; //层次。
struct upid numbers[1]; //可以再附加元素。
};
struct task_struct {
/* PID/PID hash table linkage. */
struct pid_link pids[PIDTYPE_MAX];
...
};
struct pid_link{
struct hlist_node node;
struct pid *pid;
};
两个操作:
(1) 给出task_struct和命名空间,取得局部ID
(2) 给出局部ID和命名空间,查找task_struct
操作(1)的过程:
staticinlinestruct pid *task_pid(struct task_struct *task){
return task->pids[PIDTYPE_PID].pid; /* Error?! */
}
pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) {
struct upid *upid;
pid_t nr = 0;
if (pid && ns->level <= pid->level) {
upid = &pid->numbers[ns->level];
if (upid->ns == ns)
nr = upid->nr;
}
return nr;
}
pid_t task_pid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
操作(2)的过程(内核如何将数字PID和命名空间转换为pid实例):
将struct upid按数字PID和命名空间映射存储,当给定数字PID和命名空间时,可以获取struct upid,然后根据container_of获取struct pid。struct pid中的tasks字段的第一个task_struct。
PID的分配使用位图。
进程关系:
struct task_struct {
...
struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent’s children list */
...
}
将给定进程关联到所属各个命名空间的机制
struct task_struct {
...
/* namespaces */
struct nsproxy *nsproxy;
...
}