linux进程管理与调度(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/flaoter/article/details/75449520

转载请标明出处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

猜你喜欢

转载自blog.csdn.net/flaoter/article/details/75449520