内存管理器(九)内核内存管理–进程相关数据结构
前言
前面的几篇博文都是在学习用户态内存管理,malloc与free 也研究了Glibc 的内存管理函数的实现,本来想点到位置,但是觉得还是太浅了,不够深入,遂决定,继续挖掘下去(读破万卷始见金嘛)。所以再次修改学习路线,希望最后能做出来一切实可用的东西。
毕竟本科学习阶段主要还是在于掌握原理上的东西,真的很难做出什么有实际价值的东西,但是持续的造轮子也有助于我们学习和锻炼。
基本上下来就按照两步走的策略。
第一步:
学习目标与目的:以学习kernel内存管理的思想为核心,主要是学习其数据结构设计和算法思想。
实践方式:主要就是写内核模块看看在程序运行时,内存到底发生了什么。
第二步:
主要以实践为主,准备做一个内存的监控与调整程序。但是细节与需求还没有具体设计。先完成第一步,在这个过程中总结思考吧。
基本定于这个月内能完成第一步最好,但是最好能够完成吧,然而22号还有出去金工实习,,,,
__start
废话不多说,开始说正事。
既然说到进程,就必须的说task_struct .但是我想先说下pid_t 这个类型,就先说下它吧,之前对它我还是有点疑惑的。本来还以为这是个什么结构体类型,今天正好看到源码就先说它吧。
< typedef int __kernel_pid_t; typedef __kernel_pid_t pid_t; 由此看出,pid_t 就是整形。其实书上都写了,但是如果不是我亲眼看到,怎么都不放心,强迫症没办法。。 >
现在正式来说task_struct
在我的4.0.4 内核源码中仅仅task_struct 这个进程描述符就有435行,所以我就部全部列举了,下面简要说几个重要的
struct task_struct{
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
//进程的状态,-1:不可运行 0:可运行 >0 :停止
void *stack; //栈
atomic_t usage;
unsigned int flags; /* per process flags, defined below */
//每进程标志
unsigned int ptrace;
unsigned lock_depth; /*大内核锁深度*/
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;
pid_t pid; //进程ID
pid_t tgid;
struct task_struct __rcu *real_parent; /* real parent process */(在被调试情况下)
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
/*
* children/sibling forms the list of my natural children
*/
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 */
/*
* ptraced is the list of tasks this task is using ptrace on.
* This includes both natural children and PTRACE_ATTACH targets.
* p->ptrace_entry is p’s link on the p->parent->ptraced list.
*/
struct list_head ptraced; //调试使用
struct list_head ptrace_entry;
/* PID/PID hash table linkage. */ //进程描述符和哈希表存储
struct pid_link pids[PIDTYPE_MAX];
struct list_head thread_group;
struct list_head thread_node;
struct completion *vfork_done; /* for vfork() */
int __user *set_child_tid; /* CLONE_CHILD_SETTID */
int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */
cputime_t utime, stime, utimescaled, stimescaled; //和CPU时间相关的变量
cputime_t gtime;
struct rcu_head rcu;
unsigned long nvcsw, nivcsw; /* context switch counts */ //上下文切换次数
u64 start_time; /* monotonic time in nsec */
u64 real_start_time; /* boot based time in nsec */ //记录启动时间
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt;
struct task_cputime cputime_expires;
struct list_head cpu_timers[3];
/* process credentials */
const struct cred __rcu *real_cred; /* objective and real subjective task
* credentials (COW) */
const struct cred __rcu *cred; /* effective (overridable) subjective task
* credentials (COW) */
char comm[TASK_COMM_LEN]; /* executable name excluding path 进程的名字
– access with [gs]et_task_comm (which lock
it with task_lock())
– initialized normally by setup_new_exec */
/* file system info */
int link_count, total_link_count;
/* ipc stuff */
struct sysv_sem sysvsem;
struct sysv_shm sysvshm;
/* 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; /* restored if set_restore_sigmask() was used */
struct sigpending pending;
unsigned long sas_ss_sp;
size_t sas_ss_size;
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
struct callback_head *task_works;
struct audit_context *audit_context;
/*
* cache last used pipe for splice
*/
struct pipe_inode_info *splice_pipe; //管道相关
struct page_frag task_frag;
以上就是进程描述符的基本内容。
当然这些都是静态的内核代码,我们可以从/proc 中看到更多关于进程相关信息的东西,比如每一个进程都有资源限制,且限制是动态的,此时我们就去看/proc/self/limits .就可以看到进程的限制
这就是进程的限制参数了。
进程的类型
进程一般就两个类型:
1.fork 产生的子进程
2.exec 从一个可执行二进制文件加载另一个应用程序。
两者区别就不多说了 ,很简单。