阅读理解task_struct数据结构,它包含了
进程状态、运行时间、调度信息、进程的通讯状况、task_struct型链表连接指针
、标号,决定改进程归属、可以读写打开的一些文件信息、进程上下文和内核上下文、处理器上下文、内存信息等
- struct task_struct { volatile long state; 状态信息
- unsigned long flags; //进程号,在调用fork()时给出
- int sigpending; //进程上是否有待处理的信号
- mm_segment_t addr_limit; //进程地址空间,区分内核进程与普通进程在内存存放的不同位置
- //0-0xBFFFFFFF for user-thead
- //0-0xFFFFFFFF for kernel-thread //调度标志,表示该进程是否需要重新调度,若非0,则当从内核态返回到用户态,会发生调度
- volatile long need_resched;
- int lock_depth; //锁深度
- long nice; //进程的基本时间片
- //进程的调度策略,有三种,实时进程:SCHED_FIFO,SCHED_RR, 分时进程:SCHED_OTHER unsigned long policy;
- struct mm_struct *mm; //进程内存管理信息
- int processor; //若进程不在任何CPU上运行, cpus_runnable 的值是0,否则是1 这个值在运行队列被锁时更新
- unsigned long cpus_runnable, cpus_allowed;
- struct list_head run_list; //指向运行队列的指针
- unsigned long sleep_time; //进程的睡眠时间
- //用于将系统中所有的进程连成一个双向循环链表, 其根是init_task
- struct task_struct *next_task, *prev_task;
- struct mm_struct *active_mm;
- struct list_head local_pages; //指向本地页面
- unsigned int allocation_order, nr_local_pages; struct linux_binfmt *binfmt; //进程所运行的可执行文件的格式
- int exit_code, exit_signal;
- int pdeath_signal; //父进程终止是向子进程发送的信号
- unsigned long personality;
- int did_exec:1; pid_t pid; //进程标识符,用来代表一个进程
- pid_t pgrp; //进程组标识,表示进程所属的进程组
- pid_t tty_old_pgrp; //进程控制终端所在的组标识
- pid_t session; //进程的会话标识
- pid_t tgid;
- int leader; //表示进程是否为会话主管
- struct task_struct *p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_osptr; struct list_head thread_group; //线程链表
- struct task_struct *pidhash_next; //用于将进程链入HASH表
- struct task_struct **pidhash_pprev;
- wait_queue_head_t wait_chldexit; //供wait4()使用
- struct completion *vfork_done; //供vfork() 使用
- unsigned long rt_priority; //实时优先级,用它计算实时进程调度时的weight值 ……
- };
- 进程创建分析
- fork函数到底如何进行对应的内核处理过程sys_clone。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char * argv[])
{
int pid;
/* fork another process */
-
pid = fork(); if (pid < 0) { /* error occurred */ fprintf(stderr,"Fork Failed!"); exit(-1); } else if (pid == 0) { /* child process */ printf("This is Child Process!\n"); } else { /* parent process */ printf("This is Parent Process!\n"); /* parent will wait for the child to complete*/ wait(NULL); printf("Child Complete!\n"); } }
ti = alloc_thread_info_node(tsk, node);
tsk->stack = ti;
setup_thread_stack(tsk, orig); //这里只是复制thread_info,而非复制内核堆栈
*childregs = *current_pt_regs(); //复制内核堆栈
childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址
static struct task_struct *dup_task_struct(struct task_struct *orig)
{
struct task_struct *tsk;
struct thread_info *ti;
int node = tsk_fork_get_node(orig);
int err;
tsk = alloc_task_struct_node(node);
if (!tsk)
return NULL;
ti = alloc_thread_info_node(tsk, node);
if (!ti)
goto free_tsk;
err = arch_dup_task_struct(tsk, orig);
if (err)
goto free_ti;
tsk->stack = ti;
# ifdef CONFIG_SECCOMP
tsk->seccomp.filter = NULL;
# endif
setup_thread_stack(tsk, orig);
clear_user_return_notifier(tsk);
clear_tsk_need_resched(tsk);
set_task_stack_end_magic(tsk);
# ifdef CONFIG_CC_STACKPROTECTOR
tsk->stack_canary = get_random_int();
# endif
atomic_set(&tsk->usage, 2);
# ifdef CONFIG_BLK_DEV_IO_TRACE
tsk->btrace_seq = 0;
# endif
tsk->splice_pipe = NULL;
tsk->task_frag.page = NULL;
account_kernel_stack(ti, 1);
return tsk;
free_ti:
free_thread_info(ti);
free_tsk:
free_task_struct(tsk);
return NULL;
}
int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, struct task_struct *p) { ... *childregs = *current_pt_regs(); childregs->ax = 0; if (sp) childregs->sp = sp; p->thread.ip = (unsigned long) ret_from_fork; ... }/*ret from_fork*/ENTRY(ret_from_fork)
CFI_STARTPROC
pushl_cfi %eax
call schedule_tail
GET_THREAD_INFO(%ebp)
popl_cfi %eax
pushl_cfi $0x0202 # Reset kernel eflags
popfl_cfi
jmp syscall_exit
CFI_ENDPROC
END小结:(ret_from_fork)新进程是从在ret_from_fork之前,也就是在copy_thread()函数中*childregs = *current_pt_regs();该句将父进程的regs参数赋值到子进程的内核堆栈,,使子进程拥有了SAVE ALL中压入栈的参数,故在ret from_fork时可以返回当前子进程的信息。
时间: 2024-10-13 12:38:49