代码学习inux内核驱动(五)

代码学习inux内核驱动(五)

等待队列和内核线程

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/atomic.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
#include <linux/kthread.h>

/******************************************************
等待队列:
linux驱动中,进程上下文阻塞一般就是用等待队列来实现,将进程停止在此处并睡眠下,直到条件满足时,才可通过此处,继续运行。
在睡眠等待期间,wake up时,唤起来检查条件,条件满足解除阻塞,不满足继续睡下去。
wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue) //初始化等待队列
DECLARE_WAIT_QUEUE_HEAD(name); //
wait_event(queue, condition); 
wait_event_interruptible(queue, condition);  //进入TASK_INTERRUPTIBLE进程的阻塞状态
wait_event_timeout(queue, condition, timeout); 
wait_event_interruptible_timeout(queue, condition, timeout);
wait_event_lock_irq(wq, condition, lock)
wait_event_interruptible_lock_irq(wq, condition, lock, cmd)
wait_event_interruptible_lock_irq_timeout(wq, condition, lock,  timeout)
wait_event_interruptible_exclusive  添加此进程是互斥独占进程

void wake_up(wait_queue_head_t * queue);  唤醒等待队列所有进程,所以唤醒进程需要进行条件判断,不满足时继续睡眠。
void wake_up_interruptible(wait_queue_head_t * queue);   //唤醒TASK_INTERRUPTIBLE进程
void sleep_on(wait_queue_head_t *q);

wait_queue_entry wa;
init_waitqueue_entry(&wa,&tsk);
DECLARE_WAITQUEUE(name, tsk)
void add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
add_wait_queue_exclusive  // 会设置flag WQ_FLAG_EXCLUSIVE表明此进程是互斥独占进程。
等待队列的flag为EXCLUSIVE,设置这个就是表示一次只会有一个非独占进程被唤醒,且是先进先唤醒(若先进进程条件未满足继续等待,则后进的进程会一直得不到唤醒),
当然非独占进程同样会被全部唤醒。

void remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
set_current_state()
schedule_timeout(HZ*10);

内核线程:
进程状态:R (TASK_RUNNING),S (TASK_INTERRUPTIBLE),D (TASK_UNINTERRUPTIBLE),T (TASK_STOPPED or TASK_TRACED),
Z (TASK_DEAD - EXIT_ZOMBIE),X (TASK_DEAD - EXIT_DEAD)
内核线程、没有独立的地址空间,所有内核线程的地址空间都是一样的,没有自己的地址空间

kthread_create :创建内核线程,创建后不会马上运行,调用wake_up_process后启动运行
struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt, ...);
//类似kthread_create  + wake_up_process
线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数

kthread_stop  结束线程,目标线程必须没有退出,否则会Oops
值得一提的是kthread_should_stop函数,我们需要在开启的线程中嵌入该函数并检查此函数的返回值,否则kthread_stop是不起作用的

schedule_timeout(HZ*10);休眠,需与set_current_state配合使用

******************************************************/
MODULE_AUTHOR("xyzeng");
MODULE_LICENSE("Dual BSD/GPL");

struct wait_queue_head my_queue;
struct wait_queue_entry queue_entry1,queue_entry2;
struct task_struct * ptask2;
struct task_struct * ptask1;

void timer_func(struct timer_list * timelist);

DEFINE_TIMER(my_timer,timer_func);

void timer_func(struct timer_list * timelist)
{
    printk("timer_func  enter\n");
   
    static int count = 0;
    
    if(count == 1){
        printk("timer_func  remove_wait_queue\n");
        remove_wait_queue(&my_queue, &queue_entry1); //第一次唤醒、进程1已退出,将其删除
    }
    count ++;
    printk("timer_func  enter 1\n");
    wake_up(&my_queue);                 //唤醒等待队列的所有进程
    printk("timer_func  enter 2\n");
    
    my_timer.expires = jiffies + 2*HZ;
    add_timer(&my_timer);               //2s 进行下一次唤醒
    printk("timer_func  enter 3\n");
        
}


int phtread_fun_1(void *data)
{
    printk("[%s,%d] enter!\n",__FUNCTION__,__LINE__);

  // init_waitqueue_entry(&queue_entry1, ptask1); 
  // add_wait_queue_exclusive(&my_queue,&queue_entry1);
    while(1){
        //if(kthread_should_stop()) {printk("phtread_fun_1 out!\n");break;}
        set_current_state(TASK_INTERRUPTIBLE);
        printk("phtread_fun_1 pid=%d\n",current->pid);
        schedule_timeout(HZ*10);

        printk("phtread_fun_1 schedule_timeout out!\n");
        do_exit(0); 
    }
    printk("[%s,%d] enter!\n",__FUNCTION__,__LINE__);
}

int gcondition ;
int phtread_fun_2(void *data)
{
    printk("[%s,%d] enter!\n",__FUNCTION__,__LINE__);

    //add_wait_queue_exclusive(&my_queue,&queue_entry2);
    
    while(1){
        set_current_state(TASK_INTERRUPTIBLE);
        printk("phtread_fun_2 pid=%d\n",current->pid);
        schedule_timeout(HZ*10);
       // if(gcondition) {printk("phtread_fun_2 break\n"); break;} //增加条件判断、不满足时继续睡眠。
        printk("phtread_fun_2 schedule_timeout out!\n");
        if(kthread_should_stop()) {printk("phtread_fun_2 out!\n");break;}
    }
}

static int code_case_waitqueue_init(void)
{
    printk("[%s,%d] enter!\n",__FUNCTION__,__LINE__);
    init_waitqueue_head(&my_queue); 
    my_timer.expires = jiffies + 2*HZ;  // 2s 后 进入时钟软中断
    add_timer(&my_timer);  
    
    ptask1 = kthread_create(phtread_fun_1,NULL,"task1");
    ptask2 = kthread_create(phtread_fun_2,NULL,"task2");
    if(IS_ERR(ptask1) || IS_ERR(ptask2)){
        printk("create kthread error!\n");
        return 0;
    }
    
   init_waitqueue_entry(&queue_entry2, ptask2);
   add_wait_queue_exclusive(&my_queue,&queue_entry2); 
   init_waitqueue_entry(&queue_entry1, ptask1); 
   add_wait_queue_exclusive(&my_queue,&queue_entry1);

    wake_up_process(ptask1);
    wake_up_process(ptask2);
        

    printk("[%s,%d] enter!\n",__FUNCTION__,__LINE__);
    //wait_event_timeout(my_queue, gcondition, HZ*5); 
   // wait_event(my_queue, gcondition);
    printk("[%s,%d] enter!\n",__FUNCTION__,__LINE__);
    //wait_event_interruptible(my_queue,gcondition);
    //wait_event_timeout(my_queue, gcondition, 5*HZ); 
    
    return 0;
}
static void code_case_waitqueue_exit(void)
{
     printk("[%s,%d] enter!\n",__FUNCTION__,__LINE__); 
    
     //if(ptask1 && !IS_ERR(ptask1))
     //    kthread_stop(ptask1);
     del_timer(&my_timer);
     if(ptask2  && gcondition == 0)
        kthread_stop(ptask2);    
     ptask1= NULL; 
     ptask2= NULL;
}

module_init(code_case_waitqueue_init);
module_exit(code_case_waitqueue_exit);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值