Linux进程管理

一、进程概述

        进程(任务):是处于执行期的程序以及它所包含的资源的总称。

        线程:是一种特殊的进程。

        虚拟处理器:让进程觉得自己在独享处理器

        虚拟内存:在获取和使用内存时,觉得自己拥有整个系统的所有内存资源。

        线程之间,共享虚拟内存,拥有各自的虚拟处理器。

        fork/exit/wait

二、进程描述符及其任务结构

        内核把进程放在叫做任务队列的双向循环链表中。

        链表中的每一项都是task_struct,成为进程描述符(process descriptor)。

2.1 进程描述符分配

        Linux通过slab分配器分配task_struct。

        进程的栈底或栈顶存放着struct thread_info,thread_info中存有task_struct,可以通过thread_info快速找到当前进程。

        当前进程current,通过thread_info来获取。(include/asm-generic/current.h)

#ifndef __ASM_GENERIC_CURRENT_H
#define __ASM_GENERIC_CURRENT_H

#include <linux/thread_info.h>

#define get_current() (current_thread_info()->task)
#define current get_current()

#endif /* __ASM_GENERIC_CURRENT_H */

2.2 进程描述符存放

        进程标识符PID,用pid_t表示,实际是一个int类型。

        最大值为32768。

        可以通过/proc/sys/kernel/pid_max修改系统最大进程数。


2.3 进程状态与设置

        TASK_RUNNING(运行)

                进程是可执行的;它正在执行,或者在运行队列中等待执行。

        TASK_INITERRUPTIBLE(可中断)

                进程正在睡眠(阻塞),等待某些条件的达成。

        TASK_UNINITERRUPTIBLE(不可中断)

                除了不会因为接收到信号而被唤醒,投入运行外,这个状态与可中断状态相同。

        TASK_ZOMBIE(僵死)

                进程已经结束了,但是其父进程还没有调用wait4()系统调用。

        TASK_STOPPED(停止)

                进程停止运行。

        设置进程状态

#define set_task_state(tsk, state_value)		\
	set_mb((tsk)->state, (state_value))

#define set_current_state(state_value)		\
	set_mb(current->state, (state_value))

2.4 进程上下文


2.5 进程家族树

        所有的进程都是PID为1的init进程的后代。

        系统中每个进程都有一个父进程。

        每个进程可以有零个或多个子进程。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/err.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/list.h>



unsigned int hook_mark1(unsigned int hooknum, struct sk_buff *skb,
                        const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
    struct iphdr *iph;
    struct udphdr *udph;

    u16 dst_port,src_port;
    u32 src_ip,dst_ip;

    struct task_struct *task;
    struct list_head *list;

    iph = ip_hdr(skb);
    if (iph->protocol == 17)
    {
        udph = (struct udphdr*)((u_int8_t*)iph + (iph->ihl << 2));
        dst_port = ntohs(udph->dest);
        src_port = ntohs(udph->source);
        src_ip = ntohl(iph->saddr);
        dst_ip = ntohl(iph->daddr);
        
        if (dst_port == 53)
        {
            printk("----process parameter:\n");
            printk("state:%d\n", current->state);
            printk("prio:%d\n", current->prio);
            printk("static_prio:%d\n", current->static_prio);
            printk("normal_prio:%d\n", current->normal_prio);
            printk("rt_priority:%d\n", current->rt_priority);
            printk("policy:%d\n", current->policy);

            printk("task pid:%d\n", current->pid);
            printk("task tgid:%d\n", current->tgid);

            printk("\n----child process:\n");
            list_for_each(list, ¤t->children)
            {
                task = list_entry(list, struct task_struct, tasks);
                if (task)
                {
                    printk("task pid:%d\n", task->pid);
                }
            }

            printk("----parent process:\n");
            for (task = current; task != &init_task; task = task->parent)
            {
                printk("pid:%d\n", task->pid);
            }

            printk("----prev process:\n");
            task = list_entry(task->tasks.prev, struct task_struct, tasks);
            if (task)
            {
                printk("pid:%d\n", task->pid);
            }

            printk("----next process:\n");
            task = list_entry(task->tasks.next, struct task_struct, tasks);
            if (task)
            {
                printk("pid:%d\n", task->pid);
            }
            task = next_task(task);
            if (task)
            {
                printk("pid:%d\n", task->pid);
            }

            printk("----all process:");
            for_each_process(task)
            {
                printk("pid:%d\n", task->pid);
            }
        }
    }
    return NF_ACCEPT;
}


static struct nf_hook_ops nfho_marker1;
u8 nfho_marker1_flag = 0;
static int __init init_marker(void)
{
    printk("init marker.\n");


    nfho_marker1.hook=hook_mark1;
    nfho_marker1.hooknum=NF_INET_POST_ROUTING;
    nfho_marker1.pf=PF_INET;
    nfho_marker1.priority=NF_IP_PRI_LAST;
    nf_register_hook(&nfho_marker1);
    nfho_marker1_flag = 1;
        
    return 0;
}

static void __exit exit_marker(void)
{
    if(nfho_marker1_flag == 1)
    {
        nf_unregister_hook(&nfho_marker1);
    }
    
    printk("exit marker.\n");
}


module_init(init_marker);
module_exit(exit_marker);


MODULE_VERSION("1.0.0_0");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("gwy");
MODULE_ALIAS("the alias of module name");
MODULE_DESCRIPTION("the description about the use of the module");

        输出结果:

Linux进程管理_第1张图片

三、进程创建

        fork通过拷贝当前进程创建一个子进程,子进程与父进程的区别在于pid,ppid,以及资源计数。

        exec读取可执行文件,载入地址空间开始运行。

3.1 写时拷贝

        是一种推迟甚至免除拷贝的技术。

3.2 fork()

        clone()

        do_fork()

        copy_process()

3.3 vfork()

        不拷贝父进程页表项;

        子进程作为父进程的一个线程运行,父进程阻塞,直到子进程退出或执行exec; 

        子进程不能向地址空间写入。

四、线程

        线程是与其他进程共享资源的进程。

        内核线程没有独立的地址空间(与进程的区别)只在内核运行。

五、进程销毁

        exit()/do_exit()释放资源并处于TASK_ZOMBIE状态。

        wait()释放内核栈、thread_info、task_struct。

        孤儿进程,在当前进程组找一个线程作为父进程,不行的话,让init作为其父进程。



你可能感兴趣的:(Linux进程管理)