linux内核学习之进程创建(1)

来源:互联网 发布:au软件怎么录音 编辑:程序博客网 时间:2024/06/09 18:55

    参考书籍《边干边学-Linux内核指导》,本人使用CentOS版本下的Linux,内核为2.6.18-164.el5xen

进程中的内核描述

       1.什么是进程:此乃操作系统课程的经典问题啊,进程就是一个运行的程序实体(还有很多种其他说法,意思差不多),这里有一个问题,如果一个人运行了程序bash,另一个也运行了bash,那么他们是不是同一个进程呢?按照上面的说法,他们运行的同一个程序实体,单他们不是同一个进程。这就说明前面的理解还是不够的,进程不只是一个运行中的程序,还包括这个程序中的所占据的所有系统资源:CPU,内存,网络资源,IO等等。所以上面的两个bash虽然用的同一个程序,但是他们所占用的系统组员是不一样的用ps查看当前系统中的进程列表,对于单CPU,操作系统采用一定的进程调度算法和内存管理办法解决多进程同时进行的实现。进程在内核中的描述:参见include/linux/sched.h 在Linux中为了便于管理,使用了task_struct结构来标示一个进程,每个进程都有一个task_struct。(这里我不知道是不是每一个结构就是一个传说中的PCB,进程控制块?望求解)。

Code:
  1. struct task_struct {   
  2.         volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */  
  3.         struct thread_info *thread_info;   
  4.         atomic_t usage;   
  5.         unsigned long flags;    /* per process flags, defined below */  
  6.   
  7.         int lock_depth;         /* BKL lock depth */  
  8.   
  9. #ifdef CONFIG_SMP   
  10. #ifdef __ARCH_WANT_UNLOCKED_CTXSW   
  11.         int oncpu;   
  12. #endif   
  13. #endif   
  14.         int load_weight;        /* for niceness load balancing purposes */  
  15.         int prio, static_prio, normal_prio;   
  16.         struct list_head run_list;   
  17.         struct prio_array *array;   
  18.   
  19.         unsigned short ioprio;   
  20.         unsigned int btrace_seq;   
  21.   
  22.         unsigned long sleep_avg;   
  23.         unsigned long long timestamp, last_ran;          
  24.  unsigned long long sched_time; /* sched_clock time spent running */  
  25.         enum sleep_type sleep_type;   
  26.   
  27.         unsigned long policy;   
  28.         cpumask_t cpus_allowed;   
  29.         unsigned int time_slice, first_time_slice;   
  30.   
  31. #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)   
  32.         struct sched_info sched_info;   
  33. #endif   
  34.   
  35.         struct list_head tasks;   
  36.   
  37.         struct mm_struct *mm, *active_mm;   
  38.   
  39. /* task state */  
  40.         struct linux_binfmt *binfmt;   
  41.         long exit_state;   
  42.         int exit_code, exit_signal;   
  43.         int pdeath_signal;  /*  The signal sent when the parent dies  */  
  44.         /* ??? */  
  45. ………
  46. ………
  47. …………

 

        由于Linux内核越来越复杂,模块越来越多,原先4Ktask_struct和内核栈已经变得越来越臃肿。2.6内核中把原先这个大小的内容加大到了8K,并且使用了把task_struct从这部分移走的方法,使用了一个thread_info,其中有一个指针指向task_struct结构。

    2.状态转换:

Code:
  1. /*  
  2.  * Task state bitmask. NOTE! These bits are also  
  3.  * encoded in fs/proc/array.c: get_task_state().  
  4.  *  
  5.  * We have two separate sets of flags: task->state  
  6.  * is about runnability, while task->exit_state are  
  7.  * about the task exiting. Confusing, but this way  
  8.  * modifying one set can't modify the other one by  
  9.  * mistake.  
  10.  */  
  11. #define TASK_RUNNING            0   
  12. #define TASK_INTERRUPTIBLE      1   
  13. #define TASK_UNINTERRUPTIBLE    2   
  14. #define TASK_STOPPED            4   
  15. #define TASK_TRACED             8   
  16. /* in tsk->exit_state */  
  17. #define EXIT_ZOMBIE             16   
  18. #define EXIT_DEAD               32   
  19. /* in tsk->state again */  
  20. #define TASK_NONINTERACTIVE     64   

    这里需要强调的是进程的状态,我们知道Linux中的进程调度是一个十分复杂的机制,不过Linux进程之间的转换也只有几个而已,上述代码的状态分别是运行,等待(可中断,不可中断),暂停,被跟踪,僵死,消亡等很多状态。

    3.进程标志位:为了对每个进程运行进行更细粒度的控制,还有一些进程标志位。

Code:
  1. /*  
  2.  * Per process flags  
  3.  */  
  4. #define PF_ALIGNWARN    0x00000001      /* Print alignment warning msgs */   
  5.                                         /* Not implemented yet, only for 486*/  
  6. #define PF_STARTING     0x00000002      /* being created */   
  7. #define PF_EXITING      0x00000004      /* getting shut down */   
  8. #define PF_DEAD         0x00000008      /* Dead */   
  9. #define PF_EXITPIDONE   0x00000010      /* pi exit done on shut down */   
  10. #define PF_FORKNOEXEC   0x00000040      /* forked but didn't exec */   
  11. #define PF_SUPERPRIV    0x00000100      /* used super-user privileges */   
  12. #define PF_DUMPCORE     0x00000200      /* dumped core */   
  13. #define PF_SIGNALED     0x00000400      /* killed by a signal */   
  14. #define PF_MEMALLOC     0x00000800      /* Allocating memory */   
  15. #define PF_FLUSHER      0x00001000      /* responsible for disk writeback */   
  16. #define PF_USED_MATH    0x00002000      /* if unset the fpu must be initialized before use */   
  17. #define PF_FREEZE       0x00004000      /* this task is being frozen for suspend now */   
  18. #define PF_NOFREEZE     0x00008000      /* this thread should not be frozen */   
  19. #define PF_FROZEN       0x00010000      /* frozen for system suspend */   
  20. #define PF_FSTRANS      0x00020000      /* inside a filesystem transaction */   
  21. #define PF_KSWAPD       0x00040000      /* I am kswapd */   
  22. #define PF_SWAPOFF      0x00080000      /* I am in swapoff */   
  23. #define PF_LESS_THROTTLE 0x00100000     /* Throttle me less: I clean memory */   
  24. #define PF_BORROWED_MM  0x00200000      /* I am a kthread doing use_mm */   
  25. #define PF_RANDOMIZE    0x00400000      /* randomize virtual address space */   
  26. #define PF_SWAPWRITE    0x00800000      /* Allowed to write to swap */   
  27. #define PF_SPREAD_PAGE  0x01000000      /* Spread page cache over cpuset */   
  28. #define PF_SPREAD_SLAB  0x02000000      /* Spread some slab caches over cpuset */   
  29. #define PF_MEMPOLICY    0x10000000      /* Non-default NUMA mempolicy */   
  30. #define PF_MUTEX_TESTER 0x20000000      /* Thread belongs to the rt mutex tester */   
  31. #define PF_PREEMPT_NOTIFIER 0x40000000  /* preempt notifier attached to the task */   

        具体含义参看代码注释吧.O(∩_∩)O~

        4.进程与调度:进程中有四种调度策略

Code:
  1. /*  
  2.  * Scheduling policies  
  3.  */  
  4. #define SCHED_NORMAL            0   
  5. #define SCHED_FIFO              1   
  6. #define SCHED_RR                2   
  7. #define SCHED_BATCH             3   

        每个进程都有自己的调度策略,大部分使用的是SCHED_NORMAL,有root权限的进程可以改变自己的策略。这四种策略有很大的不同,比如SCHED_FIFO和SCHED_RR属于实时进程调度,他们的优先级要高于另外2个进程。如果一个实时进程准备运行,那么调度器总是试图先调度实时进程。

        5.进程id,父进程id,兄弟进程:每个进程都有自己独立的id每个进程(除了init进程外)都是有其父进程派生出来的,并且有可能是兄弟进程,这些进程属于家族关系。

        6.用户id,组id:在task_struct中维护了一些跟文件系统权限控制相关的变量。没啥可赘述的,提供几个系统调用接口好了。

        7.进程与虚拟存储,进程的地址空间,内存分布:我们应该先学习一下地址空间的概念。

        物理地址:是真正对物理内存的地址,有多大物理内存,就有多大的地址。当然这个空间不一定是从0开始的,甚至不一定是连续的(这要根据具体的硬件设计)。出于按需调页的设计,和对进程间相互地址空间的保护,现代操作系统都引入了分页式内存管理和虚拟地址等概念。这些技术的实现,后面学到了在记笔记吧!O(∩_∩)O~

        在Linux操作系统中,每个进程都有属于自己的4G虚拟地址空间,意思是即每个进程都有属于自己的4G大小虚拟空间可以使用。当CPU访问一个地址的时候,CPU知道这个地址是什么,通过MMU,进程页表机制把它转换成一个物理地址,进行访问。如果访问的一个虚拟地址的物理地址还没有建立映射的话,将会发生一个缺页中断,将会发生一个缺页中断,系统会根据进程的权限和物理内存的实际情况建立一个物理映射。对于进程而言,这些过程都是透明的。       

        虚拟地址的好处是显而易见的:1.每次一个进程被载入内存,位置是可以不一样的。2.每个进程都有自己的地址空间

        8.进程自己的资源:从task_struct可以连接到很多属于该进程的资源。比如mm_struct, vma_struct , fs 等。每个进程有两个数据结构描述文件系统的相关信息。

        第一:fs_struct,包含指针指向的进程,fs_struct,它用来描述进程工作的文件系统的信息,包括根目录和当前工作目录的的denty,它们mount的文件系统信息,以及在umask中保存的初始的打开文件的权限。

        第二:file_struct,包含进程当前正在使用的所有文件的信息,比如进程从标准输入读并且写到标准输出,任何错误信息输出到标准出错。

       每打开一个文件,在file_struct的一个空闲文件指针被用来指向新文件结构。每个Linux进程启动时,默认会有3个文件描述符打开,他们是标准输入,标准输出,标准出错。它们的文件描述符一般是0,1,2。