linux kernel学习 (1) - 进程

一. 基本:

  •   task_struct :   定义在<linux/sched.h>, 大小约1.7K, 包含管理进程需要的所有信息 。 如:进程状态 -> state  ;  打开的文件 -> files_struct *files;  进程地址空间 ->  ;  信号 -> signal_struct *signal
  •    Current指针:获取当前进程。在x86里面,寄存器少,是通过先偏移到current_thread_info,再current_thread_info->task;  而current_thread_info就是: andl esp, 8192,回到当前栈末尾;因为thread_info在x86里面就存在末尾;
  •   State:当前状态,用set_task_state(pid, state)可以设置,状态有running, ready, interuptable
  •   遍历进程树: list_entry(task->tasks.next,  struct task_struct, tasks) 就可以遍历了, 明显  ->tasks是双向list_node
  •  fork() :  内核 = do_fork(),
    do_fork() = copy_process() + wake_up_new_task();  即先copy一个process, 再叫醒它;   wake_up => activate_task => enqueue_task;
              vfork() :就是子进程在父的页表里运行,父进程被阻塞;没有太大意义;

             线程:在内核里面,与进程的实现方式类似;


二. 调度:

       Linux是抢占式的。其优先级分实时和非实时。

  •  Nice值 & 实时优先级; 实时进程总是优先于普通进程; ps -lx, NI对应的列就是nice值; 

                nice值越小,在一个circle内进程执行时间片越长;  为 -20 - 19之间.

                用 nice 和 renice命令能够改变默认值。

  • Prio : ps -eo state,uid,pid,ppid,rtprio,time看实时进程;
  •   CFS公平调度:  在一个周期内,每个进程运行一次;运行时间为 nice /  circle;  circle越大,切换消耗越小,但是实时性降低;

实现: kernel/sched_fair.c

        task_struct -> (sched_entry)se  结构;  包含sum_exec_runtime, start_runtime, vruntime, 分别是总运行时间, 起步时间, 比例运行时间;

       update_curr()函数来更新,以下是三种常见情况:

                => schedule() -> dequeue_task() -> dequeue_entity()   进程出列

                =>  wake_up_process() -> enqueue_task()  -> enqueue_entity() 进程入列,这里enqueue_entity时会按照vruntime来排序成2叉树;

                => hrtimer_interrupt() -> tick_sched_timer() -> entity_tick()   tick中断

  •   schedule调度: 实现在sched.c,在cpu_idle()时会调用;  找到最高优先级类中,该运行的下个task;
  •   休眠队列,  通过一系列动作实现: DEFINE_WAIT()生成队列; add_wait_queue()把自己加入对列; prepare_to_wait()开始等待; 直到有其它地方wake_up()


三. 进程的抢占

        a. 每个进程都有need_resched bit位;该标志作用是:告诉内核,是否需要call schedule()来抢占了;

             中断返回 &   返回用户态 & 进程阻塞(直接调用schedule) &cpu_idle 都会引起调度;

       b. 抢占还需要判断锁,preempt_count,为0才可以抢占;

             

四. 进程的内存空间

      a. 地址空间:每进程一个,32位平坦的寻址范围。即使两进程有相同内存地址,也不相干... ??  , mm_struct

      b. 内存区域: 进程能访问的地址空间,可以通过映射(mmap)来动态增加。访问越界会有段错误。mm_struct -> (vm_area_struct *)mmap

      c. 地址段: 内存区域分段,代码 - 全局数据 - bss - 用户栈 - 内存映射文件 - 匿名映射 (堆)


      fork:

      父进程会copy_process => copy_mm(),给子进程一样的地址空间。此时当前进程的3GB~4GB的内核态虚拟地址对应的页表项被复制到新进程的页表项中,所以说所有进程共享1GB的内核态地址空间。但是对于用户态虚拟地址区域,则把它的进程页表项设置为只读,这样当其中一个进程对其进行写入操作时,do_page_fault()会分配新的物理页面,并建立映射,从而实现Copy On Write机制。这样父子可以读到一样的内存,但是子进程写时会新开物理page。

     如果加上了clone_vm标识,tsk->mm = current->mm, 就变成线程了,共享地址空间。

    

    缺页机制:

    页错误有三种:虚地址无效;虚地址有效但没映射;虚地址被保护,不能写。缺页机制就是第二种。

    假设虚拟地址域有8K,进程最初仅仅从起始虚拟地址A开始映射了一个物理页面,当该进程首次访问大于A+4KB小于A+8KB的虚拟地址时,由于这个虚拟地址没有映射物理页面,因此会触发页面故障,此时缺页中断处理函数do_page_fault()将查找该进程的vm_area_struct结构,在本例中,这个被访问的虚拟地址在合法的范围内,所以do_page_fault()会分配一个新的物理页面并为这个虚拟地址建立映射,此时该进程成功的访问到第二个物理页面。

    do_page_fault() => handle_mm_fault() => handle_pte_fault()





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值