曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5571|回复: 0
打印 上一主题 下一主题

等待队列简单实例

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2009-11-4 00:05:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这个实例基本上和 http://www.groad.net/bbs/read.php?tid-1294.html中的中断实例一样,去被在于当调用请求 read() 时,因为没有中断发生(没有可读数据),调用进程会进入睡眠。

驱动程序测试代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/fcntl.h>

#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/timer.h>

#include <linux/interrupt.h>
#include <linux/wait.h>

#define BLOCKIO_DEV_NAME    "blockiodev"
#define BLOCKIO_DEV_MAJOR    240

#define BLOCKIO_WRITE_ADDR    0x378
#define BLOCKIO_READ_ADDR    0x379
#define BLOCKIO_CTRL_ADDR    0x37A

#define BLOCKIO_IRQ        3
#define BLOCKIO_IRQ_ENABLE_MASK    0x10

#define BLOCKIO_BUFF_MAX    64

typedef struct {
    unsigned long time;
}__attribute__ ((packed)) R_BLOCKIO_INFO;

R_BLOCKIO_INFO intbuffer[BLOCKIO_BUFF_MAX];
int    intcount = 0;

DECLARE_WAIT_QUEUE_HEAD (WaitQueue_Read);

void blockio_clear (void)
{
    int lp;

    for (lp = 0; lp < BLOCKIO_BUFF_MAX; lp++)
    {
        intbuffer[lp].time = 0;
    }

    intcount = 0;
}

irqreturn_t blockio_interrupt (int irq, void *dev_id)
{
    if (intcount < BLOCKIO_BUFF_MAX) {
        intbuffer[intcount].time = get_jiffies_64();
        intcount++;
    }

    wake_up_interruptible (&WaitQueue_Read);  /*中断事件发生,唤醒进程*/

    return (IRQ_HANDLED);
}

int blockio_open (struct inode *inode, struct file *filp)
{
    if (!request_irq (BLOCKIO_IRQ, blockio_interrupt, IRQF_DISABLED, BLOCKIO_DEV_NAME, NULL)) {
        outb(BLOCKIO_IRQ_ENABLE_MASK, BLOCKIO_CTRL_ADDR);
    }

    blockio_clear ();

    return (0);
}

ssize_t blockio_read (struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
    int readcount;
    char *ptrdata;
    int loop;

    if (!intcount) {
        if (!(filp->f_flags & O_NONBLOCK)) {    /*应用程序不设置O_NONBLOCK非阻塞标志*/
            interruptible_sleep_on (&WaitQueue_Read);    /*进程睡眠*/
        } else {
            return (-EAGAIN);
        }
    }

    readcount = count / sizeof (R_BLOCKIO_INFO);
    if (readcount > intcount)
        readcount = intcount;    /*要求读的数量已超出实际可用的数量*/

    ptrdata = (char *) &intbuffer[0];   

    for (loop = 0; loop < readcount * sizeof(R_BLOCKIO_INFO); loop++)
    {
        put_user (ptrdata[loop], (char *) &buf[loop]);    /*每次以1字节传送*/
    }

    return (readcount * sizeof(R_BLOCKIO_INFO));
}

ssize_t blockio_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
    unsigned char status;
    int    loop;

    blockio_clear();

    for (loop = 0; loop < count; loop++)
    {
        get_user (status, (char *)buf);
        outb (status, BLOCKIO_WRITE_ADDR);
    }

    return (count);
}

int blockio_release (struct inode *inode, struct file *filp)
{
    outb (0x00, BLOCKIO_CTRL_ADDR);
    free_irq (BLOCKIO_IRQ, NULL);

    return (0);
}

struct file_operations blockio_fops = {
    .owner = THIS_MODULE,
    .read = blockio_read,
    .write = blockio_write,
    .open = blockio_open,
    .release = blockio_release,
};

int blockio_init (void)
{
    int result;

    result = register_chrdev (BLOCKIO_DEV_MAJOR, BLOCKIO_DEV_NAME, &blockio_fops);
   
    if (result < 0)
        return (result);

    return (0);
}

void blockio_exit (void)
{
    unregister_chrdev (BLOCKIO_DEV_MAJOR, BLOCKIO_DEV_NAME);
}

module_init (blockio_init);
module_exit (blockio_exit);

MODULE_LICENSE ("Dual BSD/GPL");

应用程序测试代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>


#define DEVICE_FILENAME "/dev/blockiodev"

typedef struct {
    unsigned long time;
}__attribute__ ((packed)) R_INT_INFO;

#define BLOCKIO_BUFF_MAX    64

int main()
{

    R_INT_INFO intbuffer[BLOCKIO_BUFF_MAX];
    int    dev;
    int    intcount;
    int    loop;
    char    buff[128];

    dev = open (DEVICE_FILENAME, O_RDWR);
    if (dev > 0) {
        printf ("start... input\n");
        intcount = read (dev, (char *)&intbuffer[0], sizeof (R_INT_INFO));

        printf ("input ok...\n");
        sleep (1);

        memset (intbuffer, 0, sizeof (intbuffer));

        printf ("read interrupt times\n");
       
        intcount = read (dev, (char *) intbuffer, sizeof (intbuffer)) / sizeof (R_INT_INFO);

        for (loop = 0; loop < intcount; loop++)
        {
            printf ("index = %d time = %ld\n", loop, intbuffer[loop].time);
        }

        printf ("led flashing ...\n");
        for (loop = 0; loop < 5; loop++)
        {
            buff[0] = 0xFF;
            write (dev, buff, 1);
            sleep (1);
            buff[0] = 0x00;
            write (dev, buff, 1);
            sleep (1);
        }

        close (dev);
    }

    return (0);
}
说明
在驱动程序中,当被应用程序调用 read() 读取数据时,如果 intcount = 0 ,则表示当前没可读数据;然后程序会检查 filp->f_flags 中是否设置了 O_NONBLOCK 值,也就是检查设备文件是否打开为非阻塞模式。若是以非阻塞模式打开,那么设备驱动程序返回 -EAGAIN 后立即结束函数;如果是阻塞模式,就会调用 interruptible_sleep_on() 函数,使调用进程进入睡眠状态。当有中断发生时,在中断处理函数里会调用 wake_up_interruptible() 函数唤醒等待队列.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 01:40 , Processed in 0.080517 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表