Linux 进程创建-基础电子_第1页
Linux 进程创建-基础电子_第2页
Linux 进程创建-基础电子_第3页
Linux 进程创建-基础电子_第4页
Linux 进程创建-基础电子_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

精品文档-下载后可编辑Linux进程创建-基础电子作者:李智敏,华清远见嵌入式学院上海分中心讲师。

在Linux内核内,进程是由相当大的一个称为task_STruct的结构表示的。此结构包含所有表示此进程所必需的数据,此外,还包含了大量的其他数据用来统计(accounTIng)和维护与其他进程的关系(父和子)。下面给出了task_struct的一小部分。task_struct位于./linux/include/linux/sched.h。

structtask_struct{

volatilelONgstate;

void*stack;

unsignedintflags;

intprio,static_prio;

structlist_headtasks;

structmm_struct*mm,*active_mm;

pid_tpid;

pid_ttgid;

structtask_struct*real_parent;

charcomm[TASK_COMM_LEN];

structthread_structthread;

structfiles_struct*files;

...

};

在task_struct中,可以看到几个预料之中的项,比如执行的状态、堆栈、一组标志、父进程、执行的线程(可以有很多)以及开放文件。对其做简单声明如下

1state变量是一些表明任务状态的比特位。常见的状态有:

1.TASK_RUNNING表示进程正在运行,或是排在运行队列中正要运行

2.TASK_INTERRUPTIBLE表示进程正在休眠

3.TASK_UNINTERRUPTIBLE表示进程正在休眠但不能叫醒

4.TASK_STOPPED表示进程停止

注:这些标志的完整列表可以在./linux/include/linux/sched.h内找到。

2flags定义了很多指示符,表明进程是否正在被创建(PF_STARTING)或退出(PF_EXITING),或是进程当前是否在分配内存(PF_MEMALLOC)。

3每个进程都会被赋予优先级(称为static_prio),但进程的实际优先级是基于加载以及其他几个因素动态决定的。优先级值越低,实际的优先级越高。

4tasks字段提供了链接列表的能力。它包含一个prev指针(指向前一个任务)和一个next指针(指向下一个任务)。

5进程的地址空间由mm和active_mm字段表示。mm代表的是进程的内存描述符,而active_mm则是前一个进程的内存描述符(为改进上下文切换时间的一种优化)。

6可执行程序的名称(不包含路径)占用comm(命令)字段。

7thread_struct则用来标识进程的存储状态。此元素依赖于Linux在其上运行的特定架构,在./linux/include/asm-i386/processor.h内有这样的一个例子。在此结构内,可以找到该进程自执行上下文切换后的存储(硬件注册表、程序计数器等)。

在很多情况下,进程都是动态创建并由一个动态分配的task_struct表示。当然init进程例外,它总是存在并由一个静态分配的task_struct表示。

Linux内所有进程的分配有两种方式。种方式是通过一个哈希表,由PID值进行哈希计算得到;第二种方式是通过双链循环表。循环表非常适合于对任务列表进行迭代。由于列表是循环的,没有头或尾;但是由于init_task总是存在,所以可以将其用作继续向前迭代的一个锚点。

任务列表无法从用户空间访问,但该问题很容易解决,方法是以模块形式向内核内插入代码。例如通过如下代码,它会迭代任务列表并会提供有关每个任务的少量信息(name、pid和parent名)。

structtask_struct*task=init_task;

/*Walkthroughthetasklist,untilwehittheinit_taskagain*/

do{

printk(KERN_INFO"***%s[%d]parent%s\n",

task-comm,task-pid,task-parent-comm);

}while((task=next_task(task))!=init_task);

注意,还可以标识当前正在运行的任务。Linux维护一个称为current的符号,代表的是当前运行的进程(类型是task_struct)。为此可使用如下代码:

printk(KERN_INFO,"Currenttaskis%s[%d]”,current-comm,current-pid);

Linux创建用户空间进程的情况与内核空间进程类似。二者底层机制是一致的,因为终都会依赖于一个名为do_fork的函数来创建新进程。

在创建内核线程时,内核会调用一个名为kernel_thread的函数(参见./linux/arch/i386/kernel/process.c),此函数执行某些初始化后会调用do_fork。

在用户空间,一个程序会调用fork,这会导致对名为sys_fork的内核函数的系统调用(参见./linux/arch/i386/kernel/process.c)。

do_fork是进程创建的基础。可以在./linux/kernel/fork.c内找到do_fork函数(以及相关函数copy_process)。

do_fork函数首先调用alloc_pidmap,该调用会分配一个新的PID。接下来,do_fork检查调试器是否在跟踪父进程。如果是,在clone_flags内设置CLONE_PTRACE标志以做好执行fork操作的准备。之后do_fork函数还会调用copy_process,向其传递这些标志、堆栈、注册表、父进程以及分配的PID。

新的进程在copy_process函数内作为父进程的一个副本创建。此函数能执行除启动进程之外的所有操作,启动进程在之后进行处理。copy_process内的步是验证CLONE标志以确保这些标志是一致的。如果不一致,就会返回EINVAL错误。接下来,询问LinuxSecurityModule(LSM)看当前任务是否可以创建一个新任务。

接下来,调用dup_task_struct函数(./linux/kernel/fork.c),这会分配一个新task_struct并将当前进程的描述符复制到其内。在新的线程堆栈设置好后,一些状态信息也会被初始化,并且会将控制返回给copy_process。控制回到copy_process后,除了其他几个限制和安全检查之外,还会执行一些常规管理,包括在新task_struct上的各种初始化。之后,会调用一系列复制函数来复制此进程的各个方面,比如复制开放文件描述符(copy_files)、复制符号信息(copy_sighand和copy_signal)、复制进程内存(copy_mm)以及终复制线程(copy_thread)。

之后,这个新任务会被指定给一个处理程序,同时对允许执行进程的处理程序进行额外的检查(cpus_allowed)。新进程的优先级从父进程的优先级继承后,执行一小部分额外的常规管理,而且控制也会被返回给do_fork。在此时

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论