linux进程管理与调度(一)

来源:互联网 发布:mac air怎么有两个账户 编辑:程序博客网 时间:2024/06/05 05:56

转载请标明出处floater的csdn blog,http://blog.csdn.net/flaoter

进程的管理与调度是所有操作系统的核心功能。从内核的角度来看,进程是内核分配资源(CPU,Memory)的重要单元,是计算机用来管理这些资源的一种抽象。从本节开始,将对linux内核的进程管理与调度子系统进行分析,其中使用的内核版本是4.4。

1 进程描述

在linux内核中,每一个进程唯一对应一个struct task_struct结构体,内核通过这些task_struct的管理实现对进程的管理。此数据结构定义在./include/linux/sched.h中,结构太过庞大,下面作为实例只列出了前面几行。

struct task_struct {    volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */    void *stack;    atomic_t usage;    unsigned int flags; /* per process flags, defined below */    unsigned int ptrace;#ifdef CONFIG_SMP    struct llist_node wake_entry;    int on_cpu;    unsigned int wakee_flips;    unsigned long wakee_flip_decay_ts;    struct task_struct *last_wakee;    int wake_cpu;#endif    int on_rq;....}

按照结构成员的用途,大体上分成了如下的类别,
(1) 基本信息。comm, pid, tgid, uid, gid, stack, on_cpu, on_rq, in_execve, in_iowait…
(2) 进程关系。real_parent, children, sibling…
(3) 状态相关。state, exit_state, exit_code…
(4) 使用内存。mm, active_mm, min_flt, maj_flt…
(5) 调度相关。prio, static_prio, normal_prio, rt_prio, sched_class, se, policy…
(6) 事件相关。utime, stime, start_time, real_start_time…
(7) 信号相关。signal, sighand, blocked, real_blocked, pending…
(8)文件系统。fs, files, nameidata…
(9) Misc

2 进程状态

进程的状态定义如下所示,

#define TASK_RUNNING        0    //R态,进程正在运行或在rq中等待运行#define TASK_INTERRUPTIBLE  1    //S态,阻塞等待资源或者信号#define TASK_UNINTERRUPTIBLE    2  //D态,阻塞等待资源#define __TASK_STOPPED      4  //暂停状态#define __TASK_TRACED       8  //跟踪状态/* in tsk->exit_state */#define EXIT_DEAD       16#define EXIT_ZOMBIE     32#define EXIT_TRACE      (EXIT_ZOMBIE | EXIT_DEAD)/* in tsk->state again */#define TASK_DEAD       64#define TASK_WAKEKILL       128#define TASK_WAKING     256#define TASK_PARKED     512#define TASK_NOLOAD     1024#define TASK_STATE_MAX      2048

状态转换的状态机如图所示,
task_state

3 进程初始化

进程的初始化是在start_kernel中的reset_init中实现的,创建了两个进程init和kthreadd。

kernel_thread(kernel_init, NULL, CLONE_FS);  //init进程创建pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); //kthread内核线程创建

创建的init进程再通过解析init.rc等文件进行用户进程的创建。

static int __ref kernel_init(void *unused){...    if (!try_to_run_init_process("/sbin/init") ||           !try_to_run_init_process("/etc/init") ||        !try_to_run_init_process("/bin/init") ||        !try_to_run_init_process("/bin/sh"))        //执行init程序,parse init.rc,创建子进程        return 0;...}

init进程与用户进程的关系如下:
init-+-adbd-+-sh—busybox
| -4*[{adbd}]
|-cndaemon
|-cp_diskserver---{cp_diskserver}
|-debuggerd
|-debuggerd64
|-drmserver-+-{Binder_1}
|
-{Binder_2}
|-gatekeeperd
|-gnss_download—2*[{gnss_download}]
|-gpsd—2*[{gpsd}]
|-healthd
|-installd
|-keystore
|-lmfs
|-lmkd
|-logd-+-{logd.auditd}
| |-{logd.control}
| |-{logd.daemon}
| |-5*[{logd.reader.per}]
| |-{logd.reader}
| `-{logd.writer}
|-main-+-.quicksearchbox-+-{ApplicationsPro}
| | |-{Binder_1}
| | |-{Binder_2}
| | |-{FinalizerDaemon}
| | |-{FinalizerWatchd}
| | |-{HeapTaskDaemon}

创建的kthreadd内核线程通过遍历kthread_create_list创建内核线程。

int kthreadd(void *unused){...    set_task_comm(tsk, "kthreadd");    for (;;) {...        spin_lock(&kthread_create_lock);        while (!list_empty(&kthread_create_list)) {            struct kthread_create_info *create;            create = list_entry(kthread_create_list.next,                        struct kthread_create_info, list);   //遍历kthread_create_list,创建子线程            list_del_init(&create->list);            spin_unlock(&kthread_create_lock);            create_kthread(create);            spin_lock(&kthread_create_lock);        }        spin_unlock(&kthread_create_lock);    }    return 0;}

kthreadd与内核线程的关系如下:
kthreadd-+-VserTestWq
|-adaptive_ts_wor
|-agdsp_access
|-ata_sff
|-aud_sblock-1-3
|-aud_sblock-1-4
|-binder
|-bioset
|-bm_perf
|-carveout_camera
|-carveout_fb
|-carveout_mm
|-carveout_overla
|-cfg80211
|-cfinteractive
|-compr drain
|-compr monitor
|-crypto
|-deferwq
|-devfreq_wq
|-dhd_dpc
|-dhd_rxf
|-dhd_watchdog_th

4 进程创建

常用的进程创建方法如下:
fork—————–用户进程
pthread_create—- 用户线程
kthread_create —-内核线程
do_fork

5 thread_info与内核栈

thread_info保存了特定体系结构的汇编代码段需要访问的那部分进程的数据。内核栈供用户进程的内核代码或内核线程使用。arm 32bit 处理器thread_info和内核栈task->stack合用2页内存空间。

union thread_union {    struct thread_info thread_info;    unsigned long stack[THREAD_SIZE/sizeof(long)];};

常用的current指针指向了当前的thread_info的task成员。

#define get_current() (current_thread_info()->task)#define current get_current()
static inline struct thread_info *current_thread_info(void){    return (struct thread_info *)        (current_stack_pointer & ~(THREAD_SIZE - 1));}

current_thread_info就是当前sp屏蔽掉低12位。
kernel_kstack

原创粉丝点击