进程调度如何找到优先级最高的进程

以下是调度器用于判断优先级最高进程的主要代码:

  1. struct task_struct *prev, *next;
  2. struct list_head *queue;
  3. struct prio_array *array;
  4. int indx;
  5. prev = current;
  6. array = rq->active;
  7. indx = sched_find_first_bit(array->bitmap);
  8. queue = array->queue + indx;
  9. next = list_entry(queue->next,struct task_struct,run_list);

我们先看看上面提到的几个数据结构和函数。

  • struct  task_struct

 内核把进程存放在叫做任务队列的双向循环链表中。链表中的每一项都是类型为task_struct(称为进程描述符)的结构。该结构在<linux/sched.h>中定义。该结构中,包含了两个结构成员struct list_head run_list和struct prio_array *array。

    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.     unsigned long ptrace;
    7.     int lock_depth;     /* BKL lock depth */
    8. #ifdef CONFIG_SMP 
    9. #ifdef __ARCH_WANT_UNLOCKED_CTXSW 
    10.     int oncpu;
    11. #endif 
    12. #endif 
    13.     int load_weight;    /* for niceness load balancing purposes */
    14.     int prio, static_prio, normal_prio;
    15.     struct list_head run_list;
    16.     struct prio_array *array;
    17.     unsigned short ioprio;
    18. #ifdef CONFIG_BLK_DEV_IO_TRACE 
    19.     unsigned int btrace_seq;
    20. #endif 
    21.     unsigned long sleep_avg;
    22.     unsigned long long timestamp, last_ran;
    23.     unsigned long long sched_time; /* sched_clock time spent running */
    24.     enum sleep_type sleep_type;
    25.     unsigned long policy;
    26.     cpumask_t cpus_allowed;
    27.     unsigned int time_slice, first_time_slice;
    28. #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) 
    29.     struct sched_info sched_info;
    30. #endif 
    31.     struct list_head tasks;
    32.     /*
    33.      * ptrace_list/ptrace_children forms the list of my children
    34.      * that were stolen by a ptracer.
    35.      */
    36.     struct list_head ptrace_children;
    37.     struct list_head ptrace_list;
    38.     struct mm_struct *mm, *active_mm;
    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.     unsigned long personality;
    46.     unsigned did_exec:1;
    47.     pid_t pid;
    48.     pid_t tgid;
    49. #ifdef CONFIG_CC_STACKPROTECTOR 
    50.     /* Canary value for the -fstack-protector gcc feature */
    51.     unsigned long stack_canary;
    52. #endif 
    53.     /* 
    54.      * pointers to (original) parent process, youngest child, younger sibling,
    55.      * older sibling, respectively.  (p->father can be replaced with 
    56.      * p->parent->pid)
    57.      */
    58.     struct task_struct *real_parent; /* real parent process (when being debugged) */
    59.     struct task_struct *parent; /* parent process */
    60.     /*
    61.      * children/sibling forms the list of my children plus the
    62.      * tasks I'm ptracing.
    63.      */
    64.     struct list_head children;  /* list of my children */
    65.     struct list_head sibling;   /* linkage in my parent's children list */
    66.     struct task_struct *group_leader;   /* threadgroup leader */
    67.     /* PID/PID hash table linkage. */
    68.     struct pid_link pids[PIDTYPE_MAX];
    69.     struct list_head thread_group;
    70.     struct completion *vfork_done;      /* for vfork() */
    71.     int __user *set_child_tid;      /* CLONE_CHILD_SETTID */
    72.     int __user *clear_child_tid;        /* CLONE_CHILD_CLEARTID */
    73.     unsigned long rt_priority;
    74.     cputime_t utime, stime;
    75.     unsigned long nvcsw, nivcsw; /* context switch counts */
    76.     struct timespec start_time;
    77. /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
    78.     unsigned long min_flt, maj_flt;
    79.     cputime_t it_prof_expires, it_virt_expires;
    80.     unsigned long long it_sched_expires;
    81.     struct list_head cpu_timers[3];
    82. /* process credentials */
    83.     uid_t uid,euid,suid,fsuid;
    84.     gid_t gid,egid,sgid,fsgid;
    85.     struct group_info *group_info;
    86.     kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
    87.     unsigned keep_capabilities:1;
    88.     struct user_struct *user;
    89. #ifdef CONFIG_KEYS 
    90.     struct key *request_key_auth;   /* assumed request_key authority */
    91.     struct key *thread_keyring; /* keyring private to this thread */
    92.     unsigned char jit_keyring;  /* default keyring to attach requested keys to */
    93. #endif 
    94.     /*
    95.      * fpu_counter contains the number of consecutive context switches
    96.      * that the FPU is used. If this is over a threshold, the lazy fpu
    97.      * saving becomes unlazy to save the trap. This is an unsigned char
    98.      * so that after 256 times the counter wraps and the behavior turns
    99.      * lazy again; this to deal with bursty apps that only use FPU for
    100.      * a short time
    101.      */
    102.     unsigned char fpu_counter;
    103.     int oomkilladj; /* OOM kill score adjustment (bit shift). */
    104.     char comm[TASK_COMM_LEN]; /* executable name excluding path
    105.                      - access with [gs]et_task_comm (which lock
    106.                        it with task_lock())
    107.                      - initialized normally by flush_old_exec */
    108. /* file system info */
    109.     int link_count, total_link_count;
    110. #ifdef CONFIG_SYSVIPC 
    111. /* ipc stuff */
    112.     struct sysv_sem sysvsem;
    113. #endif 
    114. /* CPU-specific state of this task */
    115.     struct thread_struct thread;
    116. /* filesystem information */
    117.     struct fs_struct *fs;
    118. /* open file information */
    119.     struct files_struct *files;
    120. /* namespaces */
    121.     struct nsproxy *nsproxy;
    122. /* signal handlers */
    123.     struct signal_struct *signal;
    124.     struct sighand_struct *sighand;
    125.     sigset_t blocked, real_blocked;
    126.     sigset_t saved_sigmask;     /* To be restored with TIF_RESTORE_SIGMASK */
    127.     struct sigpending pending;
    128.     unsigned long sas_ss_sp;
    129.     size_t sas_ss_size;
    130.     int (*notifier)(void *priv);
    131.     void *notifier_data;
    132.     sigset_t *notifier_mask;
    133.     
    134.     void *security;
    135.     struct audit_context *audit_context;
    136.     seccomp_t seccomp;
    137. /* Thread group tracking */
    138.     u32 parent_exec_id;
    139.     u32 self_exec_id;
    140. /* Protection of (de-)allocation: mm, files, fs, tty, keyrings */
    141.     spinlock_t alloc_lock;
    142.     /* Protection of the PI data structures: */
    143.     spinlock_t pi_lock;
    144. #ifdef CONFIG_RT_MUTEXES 
    145.     /* PI waiters blocked on a rt_mutex held by this task */
    146.     struct plist_head pi_waiters;
    147.     /* Deadlock detection and priority inheritance handling */
    148.     struct rt_mutex_waiter *pi_blocked_on;
    149. #endif 
    150. #ifdef CONFIG_DEBUG_MUTEXES 
    151.     /* mutex deadlock detection */
    152.     struct mutex_waiter *blocked_on;
    153. #endif 
    154. #ifdef CONFIG_TRACE_IRQFLAGS 
    155.     unsigned int irq_events;
    156.     int hardirqs_enabled;
    157.     unsigned long hardirq_enable_ip;
    158.     unsigned int hardirq_enable_event;
    159.     unsigned long hardirq_disable_ip;
    160.     unsigned int hardirq_disable_event;
    161.     int softirqs_enabled;
    162.     unsigned long softirq_disable_ip;
    163.     unsigned int softirq_disable_event;
    164.     unsigned long softirq_enable_ip;
    165.     unsigned int softirq_enable_event;
    166.     int hardirq_context;
    167.     int softirq_context;
    168. #endif 
    169. #ifdef CONFIG_LOCKDEP 
    170. # define MAX_LOCK_DEPTH 30UL 
    171.     u64 curr_chain_key;
    172.     int lockdep_depth;
    173.     struct held_lock held_locks[MAX_LOCK_DEPTH];
    174.     unsigned int lockdep_recursion;
    175. #endif 
    176. /* journalling filesystem info */
    177.     void *journal_info;
    178. /* VM state */
    179.     struct reclaim_state *reclaim_state;
    180.     struct backing_dev_info *backing_dev_info;
    181.     struct io_context *io_context;
    182.     unsigned long ptrace_message;
    183.     siginfo_t *last_siginfo; /* For ptrace use.  */
    184. /*
    185.  * current io wait handle: wait queue entry to use for io waits
    186.  * If this thread is processing aio, this points at the waitqueue
    187.  * inside the currently handled kiocb. It may be NULL (i.e. default
    188.  * to a stack based synchronous wait) if its doing sync IO.
    189.  */
    190.     wait_queue_t *io_wait;
    191. #ifdef CONFIG_TASK_XACCT 
    192. /* i/o counters(bytes read/written, #syscalls */
    193.     u64 rchar, wchar, syscr, syscw;
    194. #endif 
    195.     struct task_io_accounting ioac;
    196. #if defined(CONFIG_TASK_XACCT) 
    197.     u64 acct_rss_mem1;  /* accumulated rss usage */
    198.     u64 acct_vm_mem1;   /* accumulated virtual memory usage */
    199.     cputime_t acct_stimexpd;/* stime since last update */
    200. #endif 
    201. #ifdef CONFIG_NUMA 
    202.     struct mempolicy *mempolicy;
    203.     short il_next;
    204. #endif 
    205. #ifdef CONFIG_CPUSETS 
    206.     struct cpuset *cpuset;
    207.     nodemask_t mems_allowed;
    208.     int cpuset_mems_generation;
    209.     int cpuset_mem_spread_rotor;
    210. #endif 
    211.     struct robust_list_head __user *robust_list;
    212. #ifdef CONFIG_COMPAT 
    213.     struct compat_robust_list_head __user *compat_robust_list;
    214. #endif 
    215.     struct list_head pi_state_list;
    216.     struct futex_pi_state *pi_state_cache;
    217.     atomic_t fs_excl;   /* holding fs exclusive resources */
    218.     struct rcu_head rcu;
    219.     /*
    220.      * cache last used pipe for splice
    221.      */
    222.     struct pipe_inode_info *splice_pipe;
    223. #ifdef  CONFIG_TASK_DELAY_ACCT 
    224.     struct task_delay_info *delays;
    225. #endif 
    226. #ifdef CONFIG_FAULT_INJECTION 
    227.     int make_it_fail;
    228. #endif 
    229. };
  • struct  list_head

在Linux中list无处不在,如果定义一个结构使之成为链表,只需添加struct list_head结构作为它的一个成员就可以了。该结构定义在include/linux/list.h中。

    1. typedef struct list_head {
    2.         struct list_head *next, *prev;         //双向链表
    3. } list_t;
    4. #define LIST_HEAD_INIT(name) { &(name), &(name) }       
    5. #define LIST_HEAD(name) /
    6.         struct list_head name = LIST_HEAD_INIT(name)     //定义一个空的链表
    7. #define INIT_LIST_HEAD(ptr) do { /               //初始化一个已定义的列表
    8.         (ptr)->next = (ptr); (ptr)->prev = (ptr); /
    9. while (0)
  • sturct rq

调度程序中最基本的数据结构是运行队列(runqueue)。可执行队列定义于kernel/sched.c中,由结构runqueue表示。可执行队列是给定处理器上的可执行进程的链表,每个处理器一个。每个可投入运行的进程都唯一的归属于一个可执行队列。此外,可执行队列中还包含每个处理器的调度信息。每个运行队列都有两个优先级数组,一个活跃的,一个过期的,如下代码中画红色下划线所示。

    1. /*
    2.  * This is the main, per-CPU runqueue data structure.
    3.  *
    4.  * Locking rule: those places that want to lock multiple runqueues
    5.  * (such as the load balancing or the thread migration code), lock
    6.  * acquire operations must be ordered by ascending &runqueue.
    7.  */
    8. struct rq {
    9.     spinlock_t lock;
    10.     /*
    11.      * nr_running and cpu_load should be in the same cacheline because
    12.      * remote CPUs use both these fields when doing load calculation.
    13.      */
    14.     unsigned long nr_running;
    15.     unsigned long raw_weighted_load;
    16. #ifdef CONFIG_SMP
    17.     unsigned long cpu_load[3];
    18. #endif
    19.     unsigned long long nr_switches;
    20.     /*
    21.      * This is part of a global counter where only the total sum
    22.      * over all CPUs matters. A task can increase this counter on
    23.      * one CPU and if it got migrated afterwards it may decrease
    24.      * it on another CPU. Always updated under the runqueue lock:
    25.      */
    26.     unsigned long nr_uninterruptible;
    27.     unsigned long expired_timestamp;
    28.     /* Cached timestamp set by update_cpu_clock() */
    29.     unsigned long long most_recent_timestamp;
    30.     struct task_struct *curr, *idle;
    31.     unsigned long next_balance;
    32.     struct mm_struct *prev_mm;
    33.     struct prio_array *active, *expired, arrays[2];
    34.     int best_expired_prio;
    35.     atomic_t nr_iowait;
    36. #ifdef CONFIG_SMP
    37.     struct sched_domain *sd;
    38.     /* For active balancing */
    39.     int active_balance;
    40.     int push_cpu;
    41.     int cpu;        /* cpu of this runqueue */
    42.     struct task_struct *migration_thread;
    43.     struct list_head migration_queue;
    44. #endif
    45. #ifdef CONFIG_SCHEDSTATS
    46.     /* latency stats */
    47.     struct sched_info rq_sched_info;
    48.     /* sys_sched_yield() stats */
    49.     unsigned long yld_exp_empty;
    50.     unsigned long yld_act_empty;
    51.     unsigned long yld_both_empty;
    52.     unsigned long yld_cnt;
    53.     /* schedule() stats */
    54.     unsigned long sched_switch;
    55.     unsigned long sched_cnt;
    56.     unsigned long sched_goidle;
    57.     /* try_to_wake_up() stats */
    58.     unsigned long ttwu_cnt;
    59.     unsigned long ttwu_local;
    60. #endif
    61.     struct lock_class_key rq_lock_key;
    62. };
  • struct  prio_array

优先级数组在kernel/sched.c中定义,它是prio_array类型的结构体。优先级数组使可运行处理器的每一种优先级都包含一个相应的队列,这些队列又包含对应优先级上的可执行进程链表。优先级数组拥有一个优先级位图,当需要查找当前系统内优先级最高的可执行程序时,它可提高效率。MAX_PRIO定义了系统拥有的优先级个数,默认值是140。优先级位图数组由宏DECLARE_BITMAP产生。类型为unsigned long长整型,长32位,如果每一个代表一个优先级的话,140个优先级需要5个长整型才能表示,因此bitmap含有5个数组项,总共160位
    1. /*
    2.  * These are the runqueue data structures:
    3.  */
    4. struct prio_array {
    5.     unsigned int nr_active;
    6.     DECLARE_BITMAP(bitmap, MAX_PRIO+1); /* include 1 bit for delimiter */
    7.     struct list_head queue[MAX_PRIO];
    8. };
    9. #define DECLARE_BITMAP(name,bits) /
       unsigned long name[BITS_TO_LONGS(bits)]

    10. #define BITS_TO_LONGS(bits) /
       (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
  • sched_find_first_bit(array->bitmap)

该函数的功能是在活动优先级数组中找到第一个被设置的位。由下面的代码可以知道,最终实现使用了汇编代码。

    1. /*
    2.  * Every architecture must define this function. It's the fastest
    3.  * way of searching a 140-bit bitmap where the first 100 bits are
    4.  * unlikely to be set. It's guaranteed that at least one of the 140
    5.  * bits is cleared.
    6.  */
    7. static inline int sched_find_first_bit(unsigned long *b)
    8. {
    9.     return find_first_bit(b, 140);
    10. }
    11. /**
    12.  * find_first_bit - find the first set bit in a memory region
    13.  * @addr: The address to start the search at
    14.  * @size: The maximum size to search
    15.  *
    16.  * Returns the bit-number of the first set bit, not the number of the byte
    17.  * containing a bit.
    18.  */
    19. long find_first_bit(const unsigned long * addr, unsigned long size)
    20. {
    21.     return __find_first_bit(addr,size);
    22. }
    23. static inline long
    24. __find_first_bit(const unsigned long * addr, unsigned long size)
    25. {
    26.     long d0, d1;
    27.     long res;
    28.     /*
    29.      * We must test the size in words, not in bits, because
    30.      * otherwise incoming sizes in the range -63..-1 will not run
    31.      * any scasq instructions, and then the flags used by the jz
    32.      * instruction will have whatever random value was in place
    33.      * before.  Nobody should call us like that, but
    34.      * find_next_bit() does when offset and size are at the same
    35.      * word and it fails to find a one itself.
    36.      */
    37.     size += 63;
    38.     size >>= 6;
    39.     if (!size)
    40.         return 0;
    41.     asm volatile(
    42.         "   repe; scasq/n"
    43.         "   jz 1f/n"
    44.         "   subq $8,%%rdi/n"
    45.         "   bsfq (%%rdi),%%rax/n"
    46.         "1: subq %[addr],%%rdi/n"
    47.         "   shlq $3,%%rdi/n"
    48.         "   addq %%rdi,%%rax"
    49.         :"=a" (res), "=&c" (d0), "=&D" (d1)
    50.         :"0" (0ULL), "1" (size), "2" (addr),
    51.          [addr] "r" (addr) : "memory");
    52.     return res;
    53. }
  • list_entry(ptr,type,member)

list_entry作用就是通过list_head型指针ptr换算成其宿主结构的起始地址,该宿主结构是type型的,

而ptr在其宿主结构中定义为member成员。定义在内核源文件include/linux/list.h中。

list_entry(queue->next,struct task_struct,run_list)分析:queue和queue->next都是list_head结构,其宿主结构是struct task_struct,在宿主结构中,包含了一个list_head结构类型变量run_list。这句代码的主要作用是通过queue->next的地址求出它所在的sturct task_struct结构的起始地址。

  1. #define hlist_entry(ptr, type, member) container_of(ptr,type,member)

 

你可能感兴趣的:(数据结构,struct,list,NameSpaces,delay,Allocation)