linux内核设计与实现-第3章 进程管理
第3章 进程管理
-
3.2 进程描述符及任务结构
内核把进程的列表存放在叫做任务队列(task list)的双向循环链表中。32位机器,大约有1.7KB
链表的每一项都是类型为task_struct、称为进程描述符(process descriptor)的结构。
该结构定义在<linux/sched.h>文件中。进程描述符中包含一个具体进程的所有信息。
-
3.2.1 分配进程描述符
#include <asm/thread_info.h>
x86体系
struct thread_info {
struct task_struct *task;
struct exec_domain *exec_domain;
__u32 flags;
__u32 status;
__u32 cpu;
int preempt_count;
mm_segment_t addr_limit;
struct restart_block restart_block;
void *sysenter_return;
int uaccess_err;
}
-
3.2.2 进程描述符的存放
#include <linux/thread.h>
PID 最大值位32768 (short int 短整型的最大值)
可以通过修改/proc/sys/kernel/pid_max 来提高上限。
current_thread_info()->task;
-
3.2.3 进程状态
进程状态 | 描述 |
TASK_RUNNING | 运行 |
TASK_INTERRUPTIBLE | 可中断 |
TASK_UNINTERRUPTIBLE | 不可中断 |
__TATSK_TRACED | 被其他进程跟踪的进程 |
__TASK_STOPPED | 停止 |
-
3.2.4 设置当前进程状态
#include <linux/sched.h>
set_task_state(task,state);
set_current_state(state);
-
3.3.1 写时拷贝
Linux的fork() 使用写时拷贝(copy-on-write)页实现
-
3.3.2 fork()
Linux 通过clone() 系统调用实现fork().
-
3.4 线程在Linux中的实现
-
3.4.1 创建线程
线程创建和普通进程的创建类似,只不过在调用clone() 的时候要传递一些参数标志来指明需要共享的资源
clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);
clone(SIGCHLD,0); //普通的fork()
clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0); // vfork() 的实现
clone() 参数标志 <linux/sched.h>
参数标志 | 含义 |
CLONE_FILES | 父子进程共享打开的文件 |
CLONE_FS | 父子系统共享文件系统信息 |
CLONE_IDLETASK | 将PID设置为0,(只提供idle进程使用) |
CLONE_NEWNS | 为子进程创建新的命名空间 |
CLONE_PARENT | 指定子进程与父进程拥有同一个父进程 |
CLONE_PTRACE | 继续调试子进程 |
CLONE_SETTID | 将TID回写至用户空间 |
CLONE_SETTLS | 为子进程创建新的TLS |
CLONE_SIGHAND | 父进程共享信号处理函数及被阻断的信号 |
CLONE_SYSVSEM | 父子进程共享System V SEM_UNDO 语义 |
CLONE_THREAD | 父子进程放入相同的线程组 |
CLONE_VFORK | 调用vfork(),所以父进程准备睡眠等待子进程将其唤醒 |
CLONE_UNTRACED | 防止跟踪进程在子进程上强制执行CLONE_PTRACE |
CLONE_STOP | 以TASK_STOPPED状态开始进程 |
CLONE_SETTLS | 为子进程创建新的TLS(thread-local storage) |
CLONE_CHILD_CLEARTID | 清除子进程的TID |
CLONE_CHILD_SETTID | 设置子进程的TID |
CLONE_PARENT_SETTID | 设置父进程的TID |
CLONE_VM | 父子进程共享地址空间 |
3.4.2 内核线程
# include <linux/kthread.h>
// 创建内核线程
struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char namefmt[]...)
//新创建的进程处于不可运行状态,如果不通过调用wake_up_process()明确的唤醒它,它不会主动运行。
可以通过调用kthread_run()来达到。
struct task_struct *kthread_run(int (*threadfn)(void *data), void *data, const char namefmt[], ...)
// *kthread_run以宏实现的
#define kthread_run(threadfn,data,namefmt,....) \
({ \
struct task_struct *k; \
k = thread_create(threadfn, data, namefmt, ## __VA_args___;\
if (!IS_ERR(k)) \
wake_up_process(k); \
k; \
})