一、等待队列
在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_event:http://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