Linux内核开发之异步通知与异步I/O(二)

嵌入式系统 时间:2016-12-09来源:网络

  “曾经有一份真挚的爱情摆在面前,我却不懂珍惜;曾经有一个承诺,我却倍感珍惜,今天一定要好好讲讲..”

  讲讲啥,讲讲上节说的那个异步通知的例子呗,大家喜欢看代码,咋们就先上代码:

  struct globalfifo_dev

  {

  struct cdev cdev; /*cdev结构体*/

  unsigned int current_len; /*fifo有效数据长度*/

  unsigned char mem[GLOBALFIFO_SIZE]; /*全局内存*/

  struct semaphore sem; /*并发控制用的信号量*/

  wait_queue_head_t r_wait; /*阻塞读用的等待队列头*/

  wait_queue_head_t w_wait; /*阻塞写用的等待队列头*/

  struct fasync_struct *async_queue; /* 异步结构体指针,用于读 */

  };

  /*文件释放函数*/

  int globalfifo_release(struct inode *inode, struct file *filp)

  {

  /* 将文件从异步通知列表中删除 */

  globalmem_fasync( - 1, filp, 0);

  return 0;

  }

  static int globalfifo_fasync(int fd, struct file *filp, int mode)

  {

  struct globalfifo_dev *dev = filp->private_data;

  return fasync_helper(fd, filp, mode, &dev->async_queue);

  }

  /*globalfifo写操作*/

  static ssize_t globalfifo_write(struct file *filp, const char __user *buf,

  size_t count, loff_t *ppos)

  {

  struct globalfifo_dev *dev = filp->private_data; //获得设备结构体指针

  int ret;

  DECLARE_WAITQUEUE(wait, current); //定义等待队列

  down(&dev->sem); //获取信号量

  add_wait_queue(&dev->w_wait, &wait); //进入写等待队列头

  /* 等待FIFO非满 */

  if (dev->current_len == GLOBALFIFO_SIZE)

  {

  if (filp->f_flags &O_NONBLOCK)

  //如果是非阻塞访问

  {

  ret = - EAGAIN;

  goto out;

  }

  __set_current_state(TASK_INTERRUPTIBLE); //改变进程状态为睡眠

  up(&dev->sem);

  schedule(); //调度其他进程执行

  if (signal_pending(current))

  //如果是因为信号唤醒

  {

  ret = - ERESTARTSYS;

  goto out2;

  }

  down(&dev->sem); //获得信号量

  }

  /*从用户空间拷贝到内核空间*/

  if (count > GLOBALFIFO_SIZE - dev->current_len)

  count = GLOBALFIFO_SIZE - dev->current_len;

  if (copy_from_user(dev->mem + dev->current_len, buf, count))

  {

  ret = - EFAULT;

  goto out;

  }

  else

  {

  dev->current_len += count;

  printk(KERN_INFO "written %d bytes(s),current_len:%dn", count, dev

  ->current_len);

  wake_up_interruptible(&dev->r_wait); //唤醒读等待队列

  /* 产生异步读信号 */

  if (dev->async_queue)

  kill_fasync(&dev->async_queue, SIGIO, POLL_IN);

  ret = count;

  }

  out: up(&dev->sem); //释放信号量

  out2:remove_wait_queue(&dev->w_wait, &wait); //从附属的等待队列头移除

  set_current_state(TASK_RUNNING);

  return ret;

  }

  下面再给出测试程序:

  #include ...

  //接收到异步读信号的动作

  void input_handler(int signum)

  {

  printf("Receive a signal from globalfifo,signalnum:%dn",signum);

  }

  int main()

  {

  int fd, oflags;

  fd = open("/dev/globalfifo", O_RDWR, S_IRUSR | S_IWUSR);

  if (fd != - 1)

  {

  //启动信号驱动机制

  signal(SIGIO, input_handler); //让input_handler()处理SIGIO信号

  fcntl(fd, F_SETOWN, getpid());

  oflags = fcntl(fd, F_GETFL);

  fcntl(fd, F_SETFL, oflags | FASYNC);

  while(1)

  {

  sleep(100);

  }

  }

  else

  {

  printf("device open failuren");

  }

  }

  当我们加载完驱动并创建完设备节点后,运行上述程序,每当通过echo向/dev/globalfilfo写入新的数据后,input_handler将会被调用。如下所示:

  echo 0>/dev/globalfifo

  receive a signal from globalfifo ,signalnum:29

  echo 0>/dev/globalfifo

  receive a signal from globalfifo ,signalnum:29

  echo 0>/dev/globalfifo

  receive a signal from globalfifo ,signalnum:29

  通过上边实际的例子,小王,明白了吧,我的承诺也兑现了,下次咱们可要开始更高级的东西了..

关键词: Linux 异步I/O

加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW

或用微信扫描左侧二维码

相关文章


用户评论

请文明上网,做现代文明人
验证码:
查看电脑版