Chinaunix首页 | 论坛 | 博客
  • 博客访问: 55432
  • 博文数量: 28
  • 博客积分: 31
  • 博客等级: 民兵
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-05 14:33
文章分类
文章存档

2012年(28)

我的朋友

分类:

2012-12-06 16:05:10

设备访问有阻塞与非阻塞两种方式。
阻塞操作是指在执行设备操作时若不能获得资源则挂起进程,直到满足操作条件后再进行操作。被挂起的进程进入休眠状态,从运行队列移走,直到等待的条件满足。
非阻塞操作在不能进行设备操作时并不挂起,它或者放弃,或者不停的查询,直到可以进行操作为止。
阻塞的例子:
res = read(fd, &buf, 1);
if (res==1)    //当有输入时才返回
  printf("ok");

非阻塞的例子:
while(read(fd, &buf, 1) != 1); 无输入时也返回,循环尝试读取
printf("ok");

可以使用等待队列实现阻塞进程的唤醒。
定义等待队列头:wait_queue_head_t my_queue;
初始化等待队列头:init_waitqueue_head(&my_queue):
定义并初始化:DECLARE_WAIT_QUEUE_HEAD(name);
定义等待队列:DECLARE_WAITQUEUE(name,tsk);
添加或移除等待队列:void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); ...remove_...
等待事件:wait_event(queue,condition); ...interruptible(), ...timeout(), ...interruptible_timeout();当condition不满足时阻塞。与唤醒队列对应
唤醒队列: wake_up(), wake_up_interruptible() 
在队列上睡眠:sleep_on(wait_queue_head_t *q);将目前进程状态设置成TASK_UNINTERRUPTIBLE,并且定义一个等待队列,将它附属到等待队列头q,直到资源可获得,队列被唤醒。
   interruptible_sleep_on(),设置成TASK_INTERRUPTIBLE. 与唤醒队列对应。

在驱动程序中改变进程状态并且调用schedule的模板:
1,定义等待队列
2,添加等待队列
3,如果设备不可写,改变状态进程(__set_current_state())
4,并且如果为非阻塞操作(if (file->f_flags & O_NONBLOCK)则立即退出
5,否则用schedule()放弃cpu,调度其他进程执行
6,如果因为信号而被唤醒(signal_pending)则退出
7,当设备可写开始写设备缓冲区,
8,写完后将等待队列移出等待队列头,将进程状态设置为TASK_RUNNING

轮询。使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的房屋内。他们两个本质上是一样的。select()和poll()系统调用最终会引发设备驱动中的poll()函数被执行。
unsigned int (*poll)(struct file *filp, struct poll_table* wait);
第二个参数为轮询表指针,poll函数进行以下两项工作:
1,对可能引起设备文件状态变化的等待队列调用poll_wait()函数,将对应的等待队列头添加到poll_table;
2,返回表示能否对设备进行无阻塞读、写访问的掩码。
poll_wait()把当前进程添加到wait参数指定的等待列表(poll_table)中。
因此poll()函数的典型模板如下
static unsigned int xxx_poll(struct file *filp, poll_table *wait)
{
...
poll_wait(filp, &dev->r_wait, wait); //加读等待队列头
poll_wait(filp, &dev->w_wait, wait); //加写等待队列头
...

if(...) //可读
  mask |= POLLIN | POLLRDNORM;
if(...) //可写
  mask |= POLLOUT | POLLRDNORM;
return mask;
}

以下是对设备进行poll操作的应用程序。
------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include

#define FIFO_CLEAR 0x1
#define BUFFER_LEN 20
main()
{
  int fd, num;
  char rd_ch[BUFFER_LEN];
  fd_set rfds,wfds;
  
  /*以非阻塞方式打开/dev/globalmem设备文件*/
  fd = open("/dev/globalfifo", O_RDONLY | O_NONBLOCK);
  if (fd !=  - 1)
  {
    /*FIFO清0*/
    if (ioctl(fd, FIFO_CLEAR, 0) < 0)
    {
      printf("ioctl command failed\n");
    }
    while (1)
    {
      FD_ZERO(&rfds);
      FD_ZERO(&wfds);
      FD_SET(fd, &rfds);
      FD_SET(fd, &wfds);

      select(fd + 1, &rfds, &wfds, NULL, NULL); //select中第一个参数是需要检查号码最高的文件描述符加1.
      /*数据可获得*/
      if (FD_ISSET(fd, &rfds))
      {
       printf("Poll monitor:can be read\n");
      }
      /*数据可写入*/
      if (FD_ISSET(fd, &wfds))
      {
       printf("Poll monitor:can be written\n");
      }      
    }
  }

----------------------------------
没写入前结果一直循环显示可写,写入后显示可写可读,若写满则会显示可读。

阅读(902) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~