内核sem、wait_queue_head_t、timer和kernel_thread使用驱动范例

来源:互联网 发布:华为交换机端口应用acl 编辑:程序博客网 时间:2024/05/01 05:27

浅析linux内核中sem、wait_queue_head_t、timer和kernel_thread使用驱动范例

#include <linux/sched.h>

#define __TIMER_TEST_MOD1 1
#define __TIMER_TEST_MOD2 2
#define __TIMER_TEST_MOD3 3
#define __TIMER_TEST_MOD4 4
#define __TIMER_TEST_MOD5 5
#define __TIMER_TEST_MOD6 6


#define TIMER_TEST_MOD __TIMER_TEST_MOD6

static inline void restart_timer_delay(struct timer_list *timer, unsigned long msecs)
{
    mod_timer(timer,jiffies + msecs_to_jiffies(msecs));
}

struct _sgliethttp_timer
{
    wait_queue_head_t waitQ;
    struct semaphore sem;
    struct timer_list timer;
    int timer_freq;
    volatile int timer_counts;
    volatile int thread_run,thread_quited;
};
static struct _sgliethttp_timer sgliethttp_timer, *gliethttp_timer;

static void timer_func(unsigned long data)
{
    restart_timer_delay(&gliethttp_timer->timer, gliethttp_timer->timer_freq);
    gliethttp_timer->timer_counts++;
    #if (TIMER_TEST_MOD == __TIMER_TEST_MOD2)
    up(&gliethttp_timer->sem);
    #endif

    #if ( (TIMER_TEST_MOD == __TIMER_TEST_MOD3) || /
          (TIMER_TEST_MOD == __TIMER_TEST_MOD4) || /
          (TIMER_TEST_MOD == __TIMER_TEST_MOD5) || /
          (TIMER_TEST_MOD == __TIMER_TEST_MOD6) || 0/
        )
    wake_up(&gliethttp_timer->waitQ);
    //对于wait_event_interruptible_timeout和wait_event_timeout来说,
    //就是唤醒timer_thread,然后检查pre_timer_count != gliethttp_timer->timer_counts是否为真,
    //如果为真,那么将退出wait_event_interruptible_timeout和wait_event_timeout.
    #endif
}


static int timer_thread(void *data)
{
    #if ( (TIMER_TEST_MOD == __TIMER_TEST_MOD1) || /
          (TIMER_TEST_MOD == __TIMER_TEST_MOD3) || /
          (TIMER_TEST_MOD == __TIMER_TEST_MOD4) || 0/
        )
    int pre_timer_count = gliethttp_timer->timer_counts;
    #endif
    while(gliethttp_timer->thread_run)
    {
        #if (TIMER_TEST_MOD == __TIMER_TEST_MOD1)
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(HZ);printk("M");
        if(gliethttp_timer->timer_counts != pre_timer_count)
        {
            printk("L");
            pre_timer_count = gliethttp_timer->timer_counts;
        }
        #endif

        #if (TIMER_TEST_MOD == __TIMER_TEST_MOD2)
        //down_interruptible(&gliethttp_timer->sem);
        down(&gliethttp_timer->sem);
        printk("L");
        #endif

        #if (TIMER_TEST_MOD == __TIMER_TEST_MOD3)
        wait_event_timeout(gliethttp_timer->waitQ, pre_timer_count != gliethttp_timer->timer_counts, 5*HZ);
        pre_timer_count++;
        printk("L");
        #endif
        
        #if (TIMER_TEST_MOD == __TIMER_TEST_MOD4)
        wait_event_interruptible_timeout(gliethttp_timer->waitQ, pre_timer_count != gliethttp_timer->timer_counts, 5*HZ);
        pre_timer_count++;
        printk("L");
        #endif

        #if ( (TIMER_TEST_MOD == __TIMER_TEST_MOD5) || (TIMER_TEST_MOD == __TIMER_TEST_MOD6) )
        interruptible_sleep_on_timeout(&gliethttp_timer->waitQ, 5*HZ);
        printk("L");
        #endif
    }
    gliethttp_timer->thread_quited = 1;
    return 0;
}

static int init_gliethttp_timer(void)
{
    gliethttp_timer = &sgliethttp_timer;

    init_waitqueue_head(&gliethttp_timer->waitQ);
    init_MUTEX_LOCKED(&gliethttp_timer->sem);
    //init_MUTEX(&gliethttp_timer->sem);
    //sema_init(&gliethttp_timer->sem, 10);
    
    gliethttp_timer->thread_run = 1;
    gliethttp_timer->thread_quited = 0;
    gliethttp_timer->timer_counts = -1;
    gliethttp_timer->timer_freq = 100;
    setup_timer(&gliethttp_timer->timer, timer_func, gliethttp_timer->timer_freq);
    restart_timer_delay(&gliethttp_timer->timer, gliethttp_timer->timer_freq);
    kernel_thread(timer_thread, NULL, 0);
    printk(KERN_DEBUG"timer test start!/n");
    printk(KERN_EMERG"timer test start!/n");
    printk(KERN_ALERT"timer test start!/n");
    printk(KERN_CRIT"timer test start!/n");
    printk(KERN_ERR"timer test start!/n");
    printk(KERN_WARNING"timer test start!/n");
    printk(KERN_NOTICE"timer test start!/n");
    printk(KERN_INFO"timer test start!/n");
    //没咒念了,只能使用dmesg|tail来查看结果了


    return 0;
}

static void cleanup_gliethttp_timer(void)
{
    //del_timer(&timer);
    del_timer_sync(&gliethttp_timer->timer);
    
    #if (TIMER_TEST_MOD == __TIMER_TEST_MOD6)
    {
        gliethttp_timer->thread_run = 0;
        wake_up(&gliethttp_timer->waitQ);
        //如果在等待,那么唤醒timer_thread,让他去检测while(gliethttp_timer->thread_run)
        while(gliethttp_timer->thread_quited == 0)
        {
            set_current_state(TASK_INTERRUPTIBLE);
            schedule_timeout(1);
            printk("Q");
        }
    }
    #endif

    printk(KERN_DEBUG"/nGoodbye, timer test/n");
}

module_init(init_gliethttp_timer);
module_exit(cleanup_gliethttp_timer)

====================================

Makefile中内容

obj-m:=gliethttp_timer.o

然后执行:

make -C /lib/modules/`uname -r`/build M=`pwd` modules

即可编译生成出gliethttp_timer.ko

然后insmod gliethttp_timer.ko即可【gliethttp.Leith】.

原文地址:http://blog.chinaunix.net/u1/38994/showart_1130557.html

附件为:gliethttp_timer.tar.bz2