进程
一个进程就是一个正在执行程序的实例。从概念上说,进程是处于执行期的程序以及相关的资源的总称。进程不仅局限于一段可执行程序代码,通常还包含其它资源:内核数据对象、打开的文件、挂起的信号、处理器状态、内存地址空间、一个或多个执行线程等。
程序本身并不是进程,程序可以认为是磁盘上二进制代码的集合。当操作系统加载运行程序的那一时刻,即创建了新的进程。操作系统可以加载运行同一个程序多次,另一层意思是两个或多个进程可以共享同一程序代码。
在Linux中,通常调用fork()系统调用来创建一个新的进程。调用fork()的进程称为父进程,生成的新进程为子进程。fork()系统调用从内核返回两次:一次回到父进程,另一次回到子进程。
程序通过exit()系统调用退出执行。该函数会终结进程并将其占用的资源释放掉。父进程可以通过wait4()系统调用用来等待和获取子进程的退出状态。进程退出后被设置为僵死状态,直到它的父进程调用wait()或waitpid()为止。
进程状态
每个进程都有生命周期,从创建到终止。进程通过状态来体现生命周期的变化。进程状态可分为三大类:
运行态:该时刻进程占用cpu
就绪态:进程已经就绪,暂时未被cpu执行
阻塞态:等待某种外部事件发生
在Linux中,进程状态分为五种:
TASK_RUNNING:进程待执行(就绪态,在运行队列中待执行)或正在执行(运行态)
TASK_INTERRUPTIBLE:进程处于等待状态(阻塞态),等待某个条件达成后被内核唤醒,也可能因接收到信号而提前被唤醒
TASK_UNINTERRUPTIBLE:进程处于等待状态(阻塞态),不可中断,不接收任何信号,必须等待某事件发生才会被唤醒
TASK_TRACED:被其它进程跟踪,如被ptrace调试
TASK_STOPPED:进程停止执行,当进程接收到SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU信号后会进入此状态
进程的层次结构
当进程创建子进程后,父子进程会以某种形式保持关联,而子进程又可以创建更多的子进程,这样就组成一个进程的层次结构。
每个进程有且仅有一个父进程,但可以拥有0个或多个子进程。拥有同一个父进程的所有进程称为兄弟。
Linux中所有的进程都是PID为1的进程的后代。
进程描述符
内核把运行态的进程信息存放在由双向循环链表构成的任务队列中。队列中的每一项类型为struct task_struct,称为进程描述符结构,
该结构定义在文件中。进程描述符中包含一个具体进程的所有信息。
进程描述符的信息可以大致划分为以下几大类:
调度参数:进程优先级,最近消耗cpu的时间,最近睡眠的时间等。
内存映射:指向代码、数据、堆栈段或页表的指针。
信号:通过信号掩码显示哪些信号被忽略、哪些需要被捕捉、哪些暂时阻塞、哪些信号传递当中。
机器寄存器:当上下文切换时,机器寄存器的内容会被保存。
系统调用状态:当前系统调用的信息,包括参数和返回值。
文件描述符表:当某个文件被打开时,文件描述作为索引在文件描述表中定位相关文件的i节点数据结构。
统计数据:指向记录用户、系统执行时间。
内核堆栈:进程的内核部分可使用的固定堆栈。
其他:进程状态、PID、父子进程关系、用户和组标识等。
struct task_struct结构体比较大,完整的结构如下(linux-4.9.44):
struct task_struct {
#ifdef CONFIG_THREAD_INFO_IN_TASK
/*
* For reasons of header soup (see current_thread_info()), this
* must be the first element of task_struct.
*/
struct thread_info thread_info;
#endif
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
void *stack;
atomic_t usage;
unsigned int flags; /* per process flags, defined below */
unsigned int ptrace;
#ifdef CONFIG_SMP
struct llist_node wake_entry;
int on_cpu;
#ifdef CONFIG_THREAD_INFO_IN_TASK
unsigned int cpu; /* current CPU */
#endif
unsigned int wakee_flips;
unsigned long wakee_flip_decay_ts;
struct task_struct *last_wakee;
int wake_cpu;
#endif
int on_rq;
/*与调度相关的信息*/
int prio, static_prio, normal_prio;
unsigned int rt_priority;
const struct sched_class *sched_class;
struct sched_entity se;
struct sched_rt_entity rt;
#ifdef CONFIG_CGROUP_SCHED
struct task_group *sched_task_group;
#endif
struct sched_dl_entity dl;
#ifdef CONFIG_PREEMPT_NOTIFIERS
/* list of struct preempt_notifier: */
struct hlist_head preempt_notifiers;
#endif
#ifdef CONFIG_BLK_DEV_IO_TRACE
unsigned int btrace_seq;
#endif
unsigned int policy;
int nr_cpus_allowed;
cpumask_t cpus_allowed;
#ifdef CONFIG_PREEMPT_RCU
int rcu_read_lock_nesting;
union rcu_special rcu_read_unlock_special;
struct list_head rcu_node_entry;
struct rcu_node *rcu_blocked_node;
#endif /* #ifdef CONFIG_PREEMPT_RCU */
#ifdef CONFIG_TASKS_RCU
unsigned long rcu_tasks_nvcsw;
bool rcu_tasks_holdout;
struct list_head rcu_tasks_holdout_list;
int rcu_tasks_idle_cpu;
#endif /* #ifdef CONFIG_TASKS_RCU */
#ifdef CONFIG_SCHED_INFO
struct sched_info sched_info;
#endif
/*task链表*/
struct list_head tasks;
#ifdef CONFIG_SMP
struct plist_node pushable_tasks;
struct rb_node pushable_dl_tasks;
#endif
/*虚拟内存空间*/
struct mm_struct *mm, *active_mm;
/* per-thread vma caching */
u32 vmacache_seqnum;
struct vm_area_struct *vmacache[VMACACHE_SIZE];
#if defined(SPLIT_RSS_COUNTING)
struct task_rss_stat rss_stat;
#endif
/* task state */
int exit_state;
int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */
unsigned long jobctl; /* JOBCTL_*, siglock protected */
/* Used for emulating ABI behavior of previous Linux versions */
unsigned int personality;
/* scheduler bits, serialized by scheduler locks */
unsigned sched_reset_on_fork:1;
unsigned sched_contributes_to_load:1;
unsigned sched_migrated:1;
unsigned sched_remote_wakeup:1;
unsigned :0; /* force alignment to the next boundary */
/* unserialized, strictly 'current' */
unsigned in_execve:1; /* bit to tell LSMs we're in execve */
unsigned in_iowait:1;
#if !defined(TIF_RESTORE_SIGMASK)
unsigned restore_sigmask:1;
#endif
#ifdef CONFIG_MEMCG
unsigned memcg_may_oom:1;
#ifndef CONFIG_SLOB
unsigned memcg_kmem_skip_account:1;
#endif
#endif
#ifdef CONFIG_COMPAT_BRK
unsigned brk_randomized:1;
#endif
#ifdef CONFIG_CGROUPS
/* disallow userland-initiated cgroup migration */
unsigned no_cgroup_migration:1;
#endif
unsigned long atomic_flags; /* Flags needing atomic access. */
struct restart_block restart_block;
/*进程