进程管理记录。

Linux 学习笔记。

linux内核栈大小:在x86上,栈的大小是在编译时配置,可以是4KB,也可以是8KB。从历史上说,内核栈的大小是两页,这意味着32位机内核栈是8kb,而64位机是16kb。

threadinfo 在内核栈的栈底,其中有指针指向task-struct,threadinfo中包含的是和体系相关的,部分,task_struct中包含的是公共部分。

内核时同步和并发的重要性:

同步的必要性:1.任务调度。2多处理器系统smp.3中断异步到来。4linux内核抢占。

进程中 通过修改/proc/sys/kernel/pid_max可以修改pid的最大数目,默认最大值时32768。

写时拷贝时非常重要的。可以减少系统开销。

fork() vfork() __clone()都是调用clone()。然后clone调用do_fork。do_fork()完成创建的大部分工作。其定义在kernel/fork.c中。

do_fork调用copy_process。

copy_process内容:dup_task_struct 创建内核栈,thread_info 结构体和task_struct。

vfork 和fork的区别,vfork不拷贝父进程的页表项。

o1调度器对于对于大服务器的工作负载很理想,但是对于响应时间敏感的程序却有一些先天不足。

2.6内核取而代之的是cfs,完全公平调度算法。

进程分为IO消耗型和cpu消耗型,但这种划分并非绝对。

进程优先级:1/nice值越高,优先级越低。2.实时优先级越高,优先级越高,而且实时进程的优先级高于普通进程。ps -oe state,uid,pid,ppid,rtprio,time,comm 可以查看系统优先级,其中rtprio栏是优先级。

完全公平调度CFS,是一个针对普通的进程的调度类。其算法实现在sched_fair.c中。

nice值不能直接映射到时间片,原因很多:1/多个低优先级进程会使得进程切换变快。而且低优先级往往是后台进程,占的时间反而少了。2/nice值减少1,所带来的效果却决于其初值。3/必须要将时间片与定时器节拍匹配。这样系统定时器限制了两个时间片之间的差异。4/可能会为了实时进程而破坏公平原则,给特殊用例一个开后门的机会。玩弄调度器。以上问题可以通过改造解决,但是无法解决实质问题:分配绝对的时间片引发的固定的切换频率,给公平性造成了很大的变数。CFS采用的方法是对时间片分配方式进行根本性重新设计。摈弃时间片,二四号给处理器使用比重。

CFS中不在依靠nice值计算时间片,而是计算处理器运行比权重。

最小粒度:每个进程获得时间片的底线。默认情况下这个值是1ms。

目标延迟:无限小调度周期。

//

struct sched_entity { CFS调度去使用此实体结构进行记账,调度器实体结构所谓一个名为se的成员变量,嵌入进程描述符struct task_struct中。

    /* For load-balancing: */

    struct load_weight      load;

    struct rb_node          run_node;

    struct list_head        group_node;

    unsigned int            on_rq;

 

    u64             exec_start;

    u64             sum_exec_runtime;

    u64             vruntime; //记录了一个程序已经运行了多长时间,以及它还能再运行多久。它是经过了所有可运行的进程总数的标准化(加权)的,以ns为单位。

    u64             prev_sum_exec_runtime;

 

    u64             nr_migrations;

 

    struct sched_statistics     statistics;

 

#ifdef CONFIG_FAIR_GROUP_SCHED

    int             depth;

    struct sched_entity     *parent;

    /* rq on which this entity is (to be) queued: */

    struct cfs_rq           *cfs_rq;

    /* rq "owned" by this entity/group: */

    struct cfs_rq           *my_q;

#endif

 

#ifdef CONFIG_SMP

    /*

     * Per entity load average tracking.

     *

     * Put into separate cache line so it does not

     * collide with read-mostly values above.

     */

    struct sched_avg        avg ____cacheline_aligned_in_smp;

#endif

};

///

cfs调度:选择红黑树的最左边的叶节点,其存储于cfs_rq->tasks_timeline的rb_leftmost中。当此叶节点为空时,则表示树是空的,也就是进入idle。

struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)

{

    struct rb_node *left = rb_first_cached(&cfs_rq->tasks_timeline);

 

    if (!left)

        return NULL;

 

    return rb_entry(left, struct sched_entity, run_node);

}

__enqueue_entity:在rbtree中找到合适的位置,根据k值,将进程插入其中

dequeue_entity删除rbtree中的进程,发生在进程堵塞或者终止时,变为不可运行状态或者结束运行。

进程的5中状态。

TASK_RUNNING 运行。进程可执行。它正在执行或者在运行队列中等待执行。

TASK_INTERRUPTIBLE(可中断)-进程正在睡眠,阻塞。等待某条件达成。进程可接受信号被提前唤醒

TASK_UNINTERRUPTIBLE (不可中断)除了就算是接收信号也不会被唤醒或者准备投入运行外,这个状态与可打断状态相同。

_TASK_TRACED 被其他进程跟踪的进程,例如通过ptrace 对调试程序进行跟踪。

_TASK_STOPPED(停止) 进程停止执行,进程没有投入运行,也不能投入运行。通常是接收到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU.等信号的时候。此外,在调试期间接受到的任何信号,都会使进程进入到这种装太。

arm中通过内核栈寻找current的方法:

register unsigned long current_stack_point asm("sp") 定义变量current_stack_point 等于栈指针。

static inline struct thread_info *current_thread_info(void){

     return (struct thread_info *)

             (current_stack_point & ~(THREAD_SIZE -1)) //因为栈指针和threadinfo和一个联合体,theadinfo处于栈空间的地址最低处。将栈指针的  THREAD_SIZE的二进制位清0.即可得到其最低地址。刚好是threadinfo的地址。即使sp不是在栈顶,也无所谓。其前部地址刚好时不变的啦。

}

进程exit时需要释放的资源:

1.定时器。2.BSD记账信息。3。exit__mm 如果内存独占,那么释放之。4。信号,ipc信号。5.文件描述符,文件系统数据的引用计数。7.设置exit_code。8.exit_notify 通知父进程,及给子进程寻找养父。8调用schedule 调度。9由父进程释放内核栈,thread_info task_struct。

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值