现在的位置: 首页 > 综合 > 正文

Linux内核等待队列

2018年10月02日 ⁄ 综合 ⁄ 共 3176字 ⁄ 字号 评论关闭

一、等待队列

        在Linux驱动程序中,可以使用等待队列(waitqueue)来实现阻塞进程的唤醒。

        waitqueue很早就作为一种基本的功能单位出现在Linux内核里了,它以队列位基础数据结构,与进程调度机制紧密结合,能够用于实现内核中异步事件通知机制。

        等待队列可以用来同步对系统资源的访问。(信号量在内核中也依赖等待队列来实现)。

        我的理解:一个进程因为某个条件不满足而阻塞,不继续执行,另一个进程在满足条件后可以唤醒阻塞的进程。

二、使用示例

2.1 代码示例

        1. 定义wait_queue_head_t :      static wait_queue_head_t pkt_wq; //step 1 define wait_queue

        2. 初始化wait_queue_head_t :  init_waitqueue_head(&pkt_wq); //step 2 init wait_queue

        3. 一个进程中wait_event  :          wait_event(pkt_wq, udp_pkt_flag == 1 || kthread_should_stop()); //step 3 wait wait_queue and event

                深入理解wait_eventhttp://blog.csdn.net/djinglan/article/details/8150444

        4. 另一个进程中唤醒wake_up : wake_up(&pkt_wq); //step 4 wake up wait_queue

#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>

static struct task_struct *pkt_thread = NULL;

static wait_queue_head_t pkt_wq;  //step 1 define wait_queue
static s8 udp_pkt_flag = 0;       //step 1

static int thread_proc(void* arg)
{
    while (1) 
    {
        wait_event(pkt_wq, udp_pkt_flag == 1 || kthread_should_stop()); //step 3 wait wait_queue and event
        udp_pkt_flag = 0;                                               //step 3

        if (kthread_should_stop())
        {
            break;
        }
        else
        {
            printk("a udp packet send from host.\n");
        }
    }

    return 0;
}

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;

    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)
        {
            udp_pkt_flag = 1;   //step 4
            wake_up(&pkt_wq);   //step 4 wake up wait_queue
        }
    }
    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");



    //
    init_waitqueue_head(&pkt_wq);  //step 2 init wait_queue

    //
    pkt_thread = kthread_create(thread_proc, NULL, "thread");
    if (IS_ERR(pkt_thread))
    {
        printk("create thread error.\n");
        return PTR_ERR(pkt_thread);
    }
    
    wake_up_process(pkt_thread);

    //
    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);
    }

    //
    if (pkt_thread)
    {
        kthread_stop(pkt_thread);
        pkt_thread = NULL;
    }

    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");

2.2 内核中的使用

等待队列:

        文件drivers/s390/char/sclp_sdias.c中:

        static wait_queue_head_t sdias_wq;

线程在内核中的使用:

        文件arch/x86/kernel/apm_32.c                       

        static struct task_struct *kapmd_task;

Linux内核:kthread_create(线程)、SLEEP_MILLI_SEC

        http://blog.csdn.net/guowenyan001/article/details/39230181

参考资料

        linux等待队列wait_queue_head_t和wait_queue_t:http://blog.csdn.net/luoqindong/article/details/17840095

        wait_event_interruptible() 和 wake_up()的使用:http://blog.csdn.net/djinglan/article/details/8150444

        linux wait queue:http://blog.csdn.net/zacklin/article/details/7238462

抱歉!评论已关闭.