基于Linux的源代码

摘要:

    本文为基于Linux 2.6.11源代码进行的有关进程部分的简单解析。

 

一、Linux下的进程

1.进程的定义

在进程模型中,计算机上所有可运行的软件,通常也包括操作系统,被组织成若干顺序进程(sequential process),简称进程(process)。操作系统中最核心的概念是进程, 进程也是并发程序设计中的一个最重要、 最基本的概念。进程是一个动态的过程, 即进程有生命周期, 它拥有资源, 是程序的执行过程, 其状态是变化的。

 

 

 

2.为什么要引入进程

1.理论角度看,是对正在运行的程序过程的抽象;
2..实现角度看,是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。
3.进程的内容
一个计算机系统进程包括(或者说“拥有”)下列数据:
 
那个程序的可运行机器码的一个在存储器的映像。 分配到的存储器(通常包括虚拟内存的一个区域)。存储器的内容包括可运行代码、特定于进程的数据(输入、输出)、调用堆栈、堆栈(用于保存运行时运数中途产生的数据)。 分配给该进程的资源的操作系统描述符,诸如文件描述符(Unix术语)或文件句柄(Windows)、数据源和数据终端。 安全特性,诸如进程拥有者和进程的权限集(可以容许的操作)。 处理器状态(内文),诸如寄存器内容、物理存储器寻址等。当进程正在运行时,状态通常储存在寄存器,其他情况在存储器。

二、组织进程
1.task_struct 进程属性描述符
struct task_struct {
    volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
    struct thread_info *thread_info;
    atomic_t usage;
    unsigned long flags;    /* per process flags, defined below */
    unsigned long ptrace;

    int lock_depth;        /* Lock depth */

    int prio, static_prio;
    struct list_head run_list;
    prio_array_t *array;

    unsigned long sleep_avg;
    unsigned long long timestamp, last_ran;
    int activated;

    unsigned long policy;
    cpumask_t cpus_allowed;
    unsigned int time_slice, first_time_slice;

#ifdef CONFIG_SCHEDSTATS
    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;
    long exit_state;
    int exit_code, exit_signal;
    int pdeath_signal;  /*  The signal sent when the parent dies  */
    /* ??? */
    unsigned long personality;
    unsigned did_exec:1;
    pid_t pid;
    pid_t tgid;
    /* 
     * 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 pids[PIDTYPE_MAX];

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

    unsigned long rt_priority;
    unsigned long it_real_value, it_real_incr;
    cputime_t it_virt_value, it_virt_incr;
    cputime_t it_prof_value, it_prof_incr;
    struct timer_list real_timer;
    cputime_t utime, stime;
    unsigned long nvcsw, nivcsw; /* context switch counts */
    struct timespec start_time;
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
    unsigned long min_flt, maj_flt;
/* 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 *session_keyring;    /* keyring inherited over fork */
    struct key *process_keyring;    /* keyring private to this process (CLONE_THREAD) */
    struct key *thread_keyring;    /* keyring private to this thread */
#endif
    int oomkilladj; /* OOM kill score adjustment (bit shift). */
    char comm[TASK_COMM_LEN];
/* file system info */
    int link_count, total_link_count;
/* ipc stuff */
    struct sysv_sem sysvsem;
/* CPU-specific state of this task */
    struct thread_struct thread;
/* filesystem information */
    struct fs_struct *fs;
/* open file information */
    struct files_struct *files;
/* namespace */
    struct namespace *namespace;
/* signal handlers */
    struct signal_struct *signal;
    struct sighand_struct *sighand;

    sigset_t blocked, real_blocked;
    struct sigpending pending;

    unsigned long sas_ss_sp;
    size_t sas_ss_size;
    int (*notifier)(void *priv);
    void *notifier_data;
    sigset_t *notifier_mask;
    
    void *security;
    struct audit_context *audit_context;

/* 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 proc_dentry: nesting proc_lock, dcache_lock, write_lock_irq(&tasklist_lock); */
    spinlock_t proc_lock;
/* context-switch lock */
    spinlock_t switch_lock;

/* journalling filesystem info */
    void *journal_info;

/* VM state */
    struct reclaim_state *reclaim_state;

    struct dentry *proc_dentry;
    struct backing_dev_info *backing_dev_info;

    struct io_context *io_context;

    unsigned long ptrace_message;
    siginfo_t *last_siginfo; /* For ptrace use.  */
/*
 * current io wait handle: wait queue entry to use for io waits
 * If this thread is processing aio, this points at the waitqueue
 * inside the currently handled kiocb. It may be NULL (i.e. default
 * to a stack based synchronous wait) if its doing sync IO.
 */
    wait_queue_t *io_wait;
/* i/o counters(bytes read/written, #syscalls */
    u64 rchar, wchar, syscr, syscw;
#if defined(CONFIG_BSD_PROCESS_ACCT)
    u64 acct_rss_mem1;    /* accumulated rss usage */
    u64 acct_vm_mem1;    /* accumulated virtual memory usage */
    clock_t acct_stimexpd;    /* clock_t-converted stime since last update */
#endif
#ifdef CONFIG_NUMA
      struct mempolicy *mempolicy;
    short il_next;
#endif
};

其中

    1. 1)unsigned short pid 为用户标识
      (2)int pid 为进程标识
      (3)int processor标识用户正在使用的CPU,以支持对称多处理机方式;
      (4)volatile long state 标识进程的状态,可为下列六种状态之一:
        可运行状态(TASK-RUNING);
        可中断阻塞状态(TASK-UBERRUPTIBLE)
        不可中断阻塞状态(TASK-UNINTERRUPTIBLE)
        僵死状态(TASK-ZOMBLE)
        暂停态(TASK_STOPPED)
        交换态(TASK_SWAPPING)
      (5)long prority表示进程的优先级
      (6)unsigned long rt_prority 表示实时进程的优先级,对于普通进程无效
      (7)long counter 为进程动态优先级计数器,用于进程轮转调度算法
      (8)unsigned long policy 表示进程调度策略,其值为下列三种情况之一:
        SCHED_OTHER(值为0)对应普通进程优先级轮转法(round robin)
        SCHED_FIFO(值为1)对应实时进程先来先服务算法;
        SCHED_RR(值为2)对应实时进程优先级轮转法
      (9)struct task_struct *next_task,*prev_task为进程PCB双向链表的前后项指针
      (10)struct task_struct *next_run,*prev_run为就绪队列双向链表的前后项指针(11)struct task_struct *p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_ptr指明进程家族间的关系,分别为指向祖父进程、父进程、子进程以及新老进程的指针。  

2.进程的状态转换(网图侵删)

 

 

 3.进程调度

 

 __wait_event_interruptible_timeout(wq, condition, ret)        \
do {                                    \
    DEFINE_WAIT(__wait);                        \
                                    \
    for (;;) {                            \
        prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);    \
        if (condition)                        \
            break;                        \
        if (!signal_pending(current)) {                \
            ret = schedule_timeout(ret);            \
            if (!ret)                    \
                break;                    \
            continue;                    \
        }                            \
        ret = -ERESTARTSYS;                    \
        break;                            \
    }                                \
    finish_wait(&wq, &__wait);                    \
} while (0)

 

1、进程调度的时机
  进程状态转换:
  当前进程时间片用完
  设备驱动程序运行时
  从内核态返回到用户态
  从中断或系统调用中返回;
  进程重新允许抢占;

  调用该函数为主动进入休眠。

   调度程序运行时,要在所有处于可运行状态的进程中选择最值得运行的进程投入运行。

1.进程的调度策略(policy)
  SCHED_NORMAL(SCHED_OTHER):普通的分时进程
  SCHED_FIFO :先入先进的实时进程
  SCHED_RR: 时间片轮转的实时进程
  SCHED_BATCH:批处理进程,与普通进程不被抢占的情况类似
  SCHED_IDLE:CPU空闲时,即SCHED_IDLE等级以外处于可执行状态的进程消失时,将被赋予执行权。也就是它将成为优先级最低的进程。
  linux对调度策略定义如下:
 

  #define SCHED_NORMAL            0
  #define SCHED_FIFO              1
#define SCHED_RR 2
#define SCHED_BATCH 3  #define SCHED_IDLE 5

 

 

进程的调度算法:

 

  1.先来先服务FCFS:该算法即可用于作业调度,也可用于进程调度

  2.短作业优先/短进程优先 :SJF/  SPF :选择剩余时间最短的

  3.优先权优先  FPF

  4.时间片轮询法

4.对Linux进程模型的看法

一个优秀的系统无法脱离优秀的结构而存。作为一个开源的操作系统,Linux建立在许许多多志同道合的开发者的紧密合作之上。通过阅读代码,我们可以发现其书写的规范性和命名极强的可读性。也许这提醒了我们,在当前的环境下,多人协作并构筑出一个可行的标准是极其重要的。

参考材料:

https://elixir.bootlin.com/linux/v2.6.11/ident/sched_class

https://www.ibm.com/developerworks/cn/linux/l-task-killable/

https://www.cnblogs.com/ck1020/p/6089970.html

https://blog.csdn.net/shuizhilan/article/details/6642040

https://blog.csdn.net/kevin_hcy/article/details/6064518

 

 

posted @ 2018-05-01 15:59  give-he1s  阅读(2088)  评论(0编辑  收藏  举报