深入LInux内核结构学习笔记---进程表示

Linux2.6.24
struct task_struct {
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;


int lock_depth; /* BKL lock depth */


#ifdef CONFIG_SMP
#ifdef __ARCH_WANT_UNLOCKED_CTXSW
int oncpu;
#endif
#endif


int prio, static_prio, normal_prio;
struct list_head run_list;
const struct sched_class *sched_class;
struct sched_entity se;


#ifdef CONFIG_PREEMPT_NOTIFIERS
/* list of struct preempt_notifier: */
struct hlist_head preempt_notifiers;
#endif


unsigned short ioprio;
/*
* fpu_counter contains the number of consecutive context switches
* that the FPU is used. If this is over a threshold, the lazy fpu
* saving becomes unlazy to save the trap. This is an unsigned char
* so that after 256 times the counter wraps and the behavior turns
* lazy again; this to deal with bursty apps that only use FPU for
* a short time
*/
unsigned char fpu_counter;
s8 oomkilladj; /* OOM kill score adjustment (bit shift). */
#ifdef CONFIG_BLK_DEV_IO_TRACE
unsigned int btrace_seq;
#endif


unsigned int policy;
cpumask_t cpus_allowed;
unsigned int time_slice;


#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
struct sched_info sched_info;
#endif


struct list_head tasks;
/*
* ptrace_list/ptrace_children forms the list of my children
* that were stolen by a ptracer.
*/
struct list_head ptrace_children;
struct list_head ptrace_list;


struct mm_struct *mm, *active_mm;


/* task state */
struct linux_binfmt *binfmt;
int exit_state;
int exit_code, exit_signal;
int pdeath_signal;  /*  The signal sent when the parent dies  */
/* ??? */
unsigned int personality;
unsigned did_exec:1;
pid_t pid;
pid_t tgid;


#ifdef CONFIG_CC_STACKPROTECTOR
/* Canary value for the -fstack-protector gcc feature */
unsigned long stack_canary;
#endif
/* 
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively.  (p->father can be replaced with 
* p->parent->pid)
*/
struct task_struct *real_parent; /* real parent process (when being debugged) */
struct task_struct *parent; /* parent process */
/*
* children/sibling forms the list of my children plus the
* tasks I'm ptracing.
*/
struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent's children list */
struct task_struct *group_leader; /* threadgroup leader */


/* PID/PID hash table linkage. */
struct pid_link pids[PIDTYPE_MAX];
struct list_head thread_group;


struct completion *vfork_done; /* for vfork() */
int __user *set_child_tid; /* CLONE_CHILD_SETTID */
int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */


unsigned int rt_priority;
cputime_t utime, stime, utimescaled, stimescaled;
cputime_t gtime;
cputime_t prev_utime, prev_stime;
unsigned long nvcsw, nivcsw; /* context switch counts */
struct timespec start_time; /* monotonic time */
struct timespec real_start_time; /* boot based time */
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt;


   cputime_t it_prof_expires, it_virt_expires;
unsigned long long it_sched_expires;
struct list_head cpu_timers[3];


/* process credentials */
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
struct group_info *group_info;
kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
unsigned keep_capabilities:1;
struct user_struct *user;
#ifdef CONFIG_KEYS
struct key *request_key_auth; /* assumed request_key authority */
struct key *thread_keyring; /* keyring private to this thread */
unsigned char jit_keyring; /* default keyring to attach requested keys to */
#endif
char comm[TASK_COMM_LEN]; /* executable name excluding path
    - access with [gs]et_task_comm (which lock
      it with task_lock())
    - initialized normally by flush_old_exec */
/* file system info */
int link_count, total_link_count;
#ifdef CONFIG_SYSVIPC
/* ipc stuff */
struct sysv_sem sysvsem;
#endif
/* CPU-specific state of this task */
struct thread_struct thread;
/* filesystem information */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
/* namespaces */
struct nsproxy *nsproxy;
/* signal handlers */
struct signal_struct *signal;
struct sighand_struct *sighand;


sigset_t blocked, real_blocked;
sigset_t saved_sigmask; /* To be restored with TIF_RESTORE_SIGMASK */
struct sigpending pending;


unsigned long sas_ss_sp;
size_t sas_ss_size;
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
#ifdef CONFIG_SECURITY
void *security;
#endif
struct audit_context *audit_context;
seccomp_t seccomp;


/* Thread group tracking */
   u32 parent_exec_id;
   u32 self_exec_id;
/* Protection of (de-)allocation: mm, files, fs, tty, keyrings */
spinlock_t alloc_lock;


/* Protection of the PI data structures: */
spinlock_t pi_lock;


#ifdef CONFIG_RT_MUTEXES
/* PI waiters blocked on a rt_mutex held by this task */
struct plist_head pi_waiters;
/* Deadlock detection and priority inheritance handling */
struct rt_mutex_waiter *pi_blocked_on;
#endif


#ifdef CONFIG_DEBUG_MUTEXES
/* mutex deadlock detection */
struct mutex_waiter *blocked_on;
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
unsigned int irq_events;
int hardirqs_enabled;
unsigned long hardirq_enable_ip;
unsigned int hardirq_enable_event;
unsigned long hardirq_disable_ip;
unsigned int hardirq_disable_event;
int softirqs_enabled;
unsigned long softirq_disable_ip;
unsigned int softirq_disable_event;
unsigned long softirq_enable_ip;
unsigned int softirq_enable_event;
int hardirq_context;
int softirq_context;
#endif
#ifdef CONFIG_LOCKDEP
# define MAX_LOCK_DEPTH 30UL
u64 curr_chain_key;
int lockdep_depth;
struct held_lock held_locks[MAX_LOCK_DEPTH];
unsigned int lockdep_recursion;
#endif


/* journalling filesystem info */
void *journal_info;


/* stacked block device info */
struct bio *bio_list, **bio_tail;


/* VM state */
struct reclaim_state *reclaim_state;


struct backing_dev_info *backing_dev_info;


struct io_context *io_context;


unsigned long ptrace_message;
siginfo_t *last_siginfo; /* For ptrace use.  */
#ifdef CONFIG_TASK_XACCT
/* i/o counters(bytes read/written, #syscalls */
u64 rchar, wchar, syscr, syscw;
#endif
struct task_io_accounting ioac;
#if defined(CONFIG_TASK_XACCT)
u64 acct_rss_mem1; /* accumulated rss usage */
u64 acct_vm_mem1; /* accumulated virtual memory usage */
cputime_t acct_stimexpd;/* stime since last update */
#endif
#ifdef CONFIG_NUMA
   struct mempolicy *mempolicy;
short il_next;
#endif
#ifdef CONFIG_CPUSETS
nodemask_t mems_allowed;
int cpuset_mems_generation;
int cpuset_mem_spread_rotor;
#endif
#ifdef CONFIG_CGROUPS
/* Control Group info protected by css_set_lock */
struct css_set *cgroups;
/* cg_list protected by css_set_lock and tsk->alloc_lock */
struct list_head cg_list;
#endif
#ifdef CONFIG_FUTEX
struct robust_list_head __user *robust_list;
#ifdef CONFIG_COMPAT
struct compat_robust_list_head __user *compat_robust_list;
#endif
struct list_head pi_state_list;
struct futex_pi_state *pi_state_cache;
#endif
atomic_t fs_excl; /* holding fs exclusive resources */
struct rcu_head rcu;


/*
* cache last used pipe for splice
*/
struct pipe_inode_info *splice_pipe;
#ifdef CONFIG_TASK_DELAY_ACCT
struct task_delay_info *delays;
#endif
#ifdef CONFIG_FAULT_INJECTION
int make_it_fail;
#endif
struct prop_local_single dirties;
};


$1 进程结构分析
1. 状态和执行信息,如待决信号、使用的二进制格式(和其他系统二进制格式的任何仿真信息)、进程ID号(pid)、到父进程及其他有关进程的指针、优先级和程序执行有关的时间信息(CPU时间)。
2. 已分配的虚拟内存信息
3. 进程身份凭据,如用户ID、组ID以及权限等。可使用系统调用查询(修改)这些数据。
4. 使用的文件包含程序代码的二进制文件,以及进程所处理的所有文件的文件系统信息。
5. 线程信息记录该进程特定于CPU的运行时间数据(该结构的剩余字段与所使用的硬件无关)。
6. 与其它应用程序协作时所需的进程间通信有关的信息。
7. 该进程所用的信号处理程序,用于响应到来的信号。


$2 task->state:
TASK_RUNNING——意味着进程处于可运行状态。这并不是说已经为进程实际分配了CPU。进程可能会一直等到调度器选中它。该状态确保进程可以立即运行,无需等待外部事件。
TASK_INTERRUPTIBLE——是针对等待某事件或其他资源的睡眠进程设置的。在内核发送信号给该进程表明事件已经发生时,进程状态变为TASK_RUNNING,它只要调度器选中该进程即可恢复执行。
TASK_UNINTERRUPTIBLE——用于因内核指示而停用的睡眠进程。它们不能由外部信号唤醒,只能有内核亲自唤醒。
TASK_STOPPED——表示进程特意停止运行,例如,由调度器暂停。
TASK_TRACED——不是进程状态,用于从停止的进程中,将当前被调试的那些(使用ptrace机制)与常规的进程区分开。


$3 task->state或task->exit_state:
EXIT_ZOMBIE——僵尸状态,该进程已经死亡,但仍然以某种方式活着。实际上,说该进程死了,是因为其资源(内存、与外设的连接等等)已经释放,因此它们无法也绝不会再次运行。说它们仍然活着,是因为进程表中仍然有对应的表项。
EXIT_DEAD——指wait系统调用已经发出,而进程完全从系统移除之前的状态。只有多个线程对同一个进程发出wait调用时,该状态才有意义。


$4 僵尸进程如何产生的?
起源应在于UNIX操作系统下进程创建和销毁的方式。在两种事件发生时,程序将终止运行。第一,程序必须有另一个进程或一个用户杀死(通常是通过发送SIGTERM或SIGKILL信号来完成,这等价于正常地终止进程);第二,进程的父进程在子进程终止时必须调用或已经调用wait4系统调用。这相当于向内核证实父进程已经确认子进程的终结。该系统调用使得内核可以释放为子进程保留的资源。
只有第一个条件发生(程序终止)而第二个条件不成立的情况下(wait4),才会出现僵尸状态。在进程终止之后,其数据尚未从进程表删除之前,进程总是暂时处于僵尸状态。有时候(如果父进程变成极其糟糕,没有发出wait调用),僵尸进程可能稳定的寄生于进程表中,直至下次系统重启。从进程工具(ps或top)的输出,可以看到僵尸进程。因为残留的数据在内核中占据的空间极少,所以这几乎不是一个问题。


$5 task->signal->rlim——Linux提供资源限制机制,对进程实用系统资源施加某些限制
struct signal_struct {
......
struct rlimit rlim[RLIM_NLIMITS];
......
};


struct rlimit {
unsigned long rlim_cur;
unsigned long rlim_max;
};
该结构有意定义地非常通用,这样它可以接受许多不同的资源类型。
rlim_cur——进程当前的资源限制,也称为软限制(soft limit)
rlim_max——限制的最大允许值,也称为硬限制(hard limit)
系统调用setrlimit来增减当前限制,但不能超过rlim_max指定的值。getrlimits用于检查当前限制。
rlim数组中的的位置标识了受限制资源的类型,这也是内核需要定义预处理器常数,将资源与位置关联起来的原因。
wei.li@Technology102:~$ cat /proc/self/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             unlimited            unlimited            processes
Max open files            1024                 1024                 files
Max locked memory         65536                65536                bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       16382                16382                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         20                   20
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us


$6 进程类型
典型的UNIX进程包括:由二进制代码组成的应用程序、单线程(计算机沿单一路径通过代码,不会有其他路径同时运行)、分配给应用程序的一组资源(内存,文件)。新进程是使用fork和exec系统调用产生的。
* fork生成当前进程的一个相同副本,该副本称之为子进程。原进程的所有资源都以适当的方式复制到子进程,因此该系统调用之后,原来的进程就有了两个独立的实例。这两个实例的联系包括:同一组打开的文件、同样的工作目录、内存中同样的数据(两个进程各有一个副本)等等。此外二者别无关联。
* exec从一个可执行的二进制文件加载另一个应用程序,来代替当前运行的进程。换句话说就是加载了一个新程序。因为exec并不创建新进程,所以必须首先使用fork复制一个旧的程序,然后调用exec在系统上创建另一个应用程序。
* clone的工作原理基本上与fork相同,但新进程不是独立于父进程的,而可以与其共享某些资源。可以指定需要复制和共享的资源种类。clone用于实现线程,但仅仅该系统调用不足以做到这一点,还需要用户空间才能提供完整的实现。线程库的例子有Linuxthreads和Next Generation Posix Threads等。


$7 命名空间
命名空间提供了虚拟化的一种轻量级形式,使得我们可以从不同的方面来查看运行系统的全局属性。
$7.1 概念
命名空间建立了系统的不同视图。此前的每一项全局资源都必须包装到容器数据结构中,只有资源和包含资源的命名空间构成的二元组仍然是全局唯一的。虽然在给定容器内部资源是充足的,但无法提供在容器外部具有唯一的ID。
命名空间可以按层次关联。父命名空间衍生子命名空间。由于相同的PID在系统中出现多次,PID号不是全局唯一的。虽然子命名空间不了解系统中的其他命名空间,但父命名空间知道子命名空间的存在,也可以看到其中执行的所有进程。
如果命名空间包含很少数量的进程,也可以是非层次的。UTS命名空间的父子命名空间之间就没有联系。
$7.2 创建方式
命名空间可以用以下两种方式创建:
(1)在用fork或clone系统调用创建新进程是,有特定的选项可以控制是于父进程共享命名空间,还是建立新的命名空间。
(2)unshare系统调用将进程的某些部分从父进程分离,其中也包括命名空间。
在进程已经使用上述的两种机制之一从父进程命名空间分离后,从该进程的角度来看,改变全局属性不会传播到父进程命名空间,而父进程的修改也不会传播到子进程,至少对于简单的量是这样。而对于文件系统来说,情况就比较复杂,其中的共享机制非常强大,带来了大量的可能性。相关信息可以参见Documentation/namespaces/compatibility-list.txt文件。
$7.3 实现
命名空间的实现需要两个部分:每个子系统的命名空间结构,将此前所有的全局组件包装到命名空间中;将给定进程关联到所属各个命名空间的机制。
子系统此前的全局属性现在封装到命名空间中,每个进程关联到一个特定的命名空间。每个可以感知命名空间的内核子系统都必须提供一个数据结构,将所有通过命名空间形式提供的对象集中起来。struct nsproxy用于汇集指向特定于子系统的命名空间包装器的指针:
/*
 * A structure to contain pointers to all per-process
 * namespaces - fs (mount), uts, network, sysvipc, etc.
 *
 * 'count' is the number of tasks holding a reference.
 * The count for each namespace, then, will be the number
 * of nsproxies pointing to it, not the number of tasks.
 *
 * The nsproxy is shared by tasks which share all namespaces.
 * As soon as a single namespace is cloned or unshared, the
 * nsproxy is copied.
 */
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 :运行内核的名称、版本、底层体系结构类型等信息。UTS是UNIX Timesharing System的简称。
IPC :所有与进程间通信(IPC)有关的信息。
MNT :已装载的文件系统的视图。
USER:保存限制每个用户资源使用的信息。
NET :所有网络相关的命名空间参数。
#define CLONE_NEWUTS 0x04000000 /* New utsname group? */
#define CLONE_NEWIPC 0x08000000 /* New ipcs */
#define CLONE_NEWUSER 0x10000000 /* New user namespace */
#define CLONE_NEWPID 0x20000000 /* New pid namespace */
#define CLONE_NEWNET 0x40000000 /* New network namespace */
struct task_struct {
...
/* namespaces */
struct nsproxy *nsproxy;
...
}
因为使用了指针,多个进程可以共享一组子命名空间。这样,修改给定的命名空间,对所有属于该命名空间的进程都是可见的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值