中国建设银行信用卡网站,网站在哪里搜索,东阳网站建设yw126,医疗营销的网站怎么做一、五种IO模型------读写外设数据的方式 阻塞: 不能操作就睡觉 非阻塞#xff1a;不能操作就返回错误 多路复用#xff1a;委托中介监控 信号驱动#xff1a;让内核如果能操作时发信号#xff0c;在信号处理函数中操作 异步IO#xff1a;向内核注册操作请求…一、五种IO模型------读写外设数据的方式 阻塞: 不能操作就睡觉 非阻塞不能操作就返回错误 多路复用委托中介监控 信号驱动让内核如果能操作时发信号在信号处理函数中操作 异步IO向内核注册操作请求内核完成操作后发通知信号
二、阻塞与非阻塞 应用层 open时由O_NONBLOCK指示read、write时是否阻塞
open以后可以由fcntl函数来改变是否阻塞
flags fcntl(fd,F_GETFL,0);
flags | O_NONBLOCK;
fcntl(fd, F_SETFL, flags);驱动层通过等待队列 wait_queue_head_t //等待队列头数据类型init_waitqueue_head(wait_queue_head_t *pwq) //初始化等待队列头wait_event_interruptible(wq,condition)
/*
功能条件不成立则让任务进入浅度睡眠直到条件成立醒来wq:等待队列头conditionC语言表达式
返回正常唤醒返回0信号唤醒返回非0此时读写操作函数应返回-ERESTARTSYS
*/wait_event(wq,condition) //深度睡眠wake_up_interruptible(wait_queue_head_t *pwq)wake_up(wait_queue_head_t *pwq)/*
1. 读、写用不同的等待队列头rq、wq
2. 无数据可读、可写时调用wait_event_interruptible(rq、wq,条件)
3. 写入数据成功时唤醒rq读出数据成功唤醒wq
*/
示例 mychar.h
#ifndef MY_CHAR_H
#define MY_CHAR_H#include asm/ioctl.h#define MY_CHAR_MAGIC c#define MYCHAR_IOCTL_GET_MAXLEN _IOR(MY_CHAR_MAGIC, 1, int *)
#define MYCHAR_IOCTL_GET_CURLEN _IOR(MY_CHAR_MAGIC, 2, int *)#endif
mychar.c
#include linux/module.h
#include linux/kernel.h
#include linux/fs.h
#include linux/cdev.h
#include linux/wait.h
#include linux/sched.h
#include asm/uaccess.h
#include asm/ioctl.h#include mychar.h#define BUF_LEN 100int major 11; //主设备号
int minor 0; //次设备号
int char_num 1; //设备号数量struct mychar_dev
{struct cdev mydev;char mydev_buf[BUF_LEN];int curlen;wait_queue_head_t rq;wait_queue_head_t wq;
};
struct mychar_dev gmydev;int mychar_open (struct inode *pnode, struct file *pfile)//打开设备
{pfile-private_data (void *) (container_of(pnode-i_cdev, struct mychar_dev, mydev));printk(open\n);return 0;
}int mychar_close(struct inode *pnode, struct file *pfile)//关闭设备
{printk(close\n);return 0;
}ssize_t mychar_read (struct file *pfile, char __user *puser, size_t count, loff_t *p_pos) {struct mychar_dev *pmydev (struct mychar_dev *)pfile-private_data;int size 0;int ret 0;/* 判断是否有数据可读 */if(pmydev-curlen 0) {if(pfile-f_flags O_NONBLOCK) { //非阻塞printk(O_NONBLOCK Not Data Read\n);return -1;} else { //阻塞/* 睡眠 当curlen0 时返回 */ret wait_event_interruptible(pmydev-rq, pmydev-curlen 0);if(ret) {return -ERESTARTSYS;}}}// 确定要读取的数据长度如果请求大于设备当前数据长度则读取全部可用数据if (count pmydev-curlen) {size pmydev-curlen;}else {size count;}// 将设备数据复制到用户空间缓冲区ret copy_to_user(puser, pmydev-mydev_buf, size);if(ret) {printk(copy_to_user failed\n);return -1;}// 移动设备内部缓冲区去除已读取的数据memcpy(pmydev-mydev_buf, pmydev-mydev_buf size, pmydev-curlen - size);pmydev-curlen - size;wake_up_interruptible(pmydev-wq);// 返回实际读取的字节数return size;
}ssize_t mychar_write (struct file *pfile, const char __user *puser, size_t count, loff_t *p_pos) {struct mychar_dev *pmydev (struct mychar_dev *)pfile-private_data;int size 0;int ret 0;if(pmydev-curlen BUF_LEN) {if(pfile-f_flags O_NONBLOCK) { //非阻塞printk(O_NONBLOCK Can Not Write Data\n);return -1;} else { //阻塞ret wait_event_interruptible(pmydev-wq, pmydev-curlen BUF_LEN);if(ret) {return -ERESTARTSYS;}}}// 确定要写入的数据长度如果请求大于设备缓冲区剩余空间则写入剩余空间大小if (count BUF_LEN - pmydev-curlen) {size BUF_LEN - pmydev-curlen;}else {size count;}// 从用户空间复制数据到设备缓冲区ret copy_from_user(pmydev-mydev_buf pmydev-curlen, puser, size);if(ret) {printk(copy_from_user failed\n);return -1;}// 更新设备缓冲区中的数据长度pmydev-curlen size;/* 唤醒读阻塞 */wake_up_interruptible(pmydev-rq);// 返回实际写入的字节数return size;
}long mychar_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{struct mychar_dev *pmydev (struct mychar_dev *)pfile-private_data;int __user *pret (int *)arg;int maxlen BUF_LEN;int ret 0;switch(cmd) {case MYCHAR_IOCTL_GET_MAXLEN:ret copy_to_user(pret, maxlen, sizeof(int));if(ret) {printk(copy_from_user failed\n);return -1;}break;case MYCHAR_IOCTL_GET_CURLEN:ret copy_to_user(pret, pmydev-curlen, sizeof(int));if(ret) {printk(copy_from_user failed\n);return -1;}break;default:printk(The is a know\n);return -1;}return 0;
}struct file_operations myops {.owner THIS_MODULE,.open mychar_open,.read mychar_read,.write mychar_write,.unlocked_ioctl mychar_ioctl,
};int __init mychar_init(void)
{int ret 0;dev_t devno MKDEV(major, minor);/* 手动申请设备号 */ret register_chrdev_region(devno, char_num, mychar);if (ret) {/* 动态申请设备号 */ret alloc_chrdev_region(devno, minor, char_num, mychar);if(ret){printk(get devno failed\n);return -1;}/*申请成功 更新设备号*/major MAJOR(devno);}/* 给struct cdev对象指定操作函数集 */cdev_init(gmydev.mydev, myops);/* 将struct cdev对象添加到内核对应的数据结构中 */gmydev.mydev.owner THIS_MODULE;cdev_add(gmydev.mydev, devno, char_num);/* 初始化 */init_waitqueue_head(gmydev.rq);init_waitqueue_head(gmydev.wq);return 0;
}void __exit mychar_exit(void)
{dev_t devno MKDEV(major, minor);printk(exit %d\n, devno);/* 从内核中移除一个字符设备 */cdev_del(gmydev.mydev);/* 回收设备号 */unregister_chrdev_region(devno, char_num);}MODULE_LICENSE(GPL);
module_init(mychar_init);
module_exit(mychar_exit);
testmychar_blockwait.c
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include string.h
#include sys/ioctl.h#include mychar.h
int main(int argc, char *argv[])
{int fd -1;char buf[100];if(argc 2) {printf(The argument is too few\n);return -1;}fd open(argv[1], O_RDWR);if(fd 0) {perror(open);return -1;}memset(buf, C, sizeof(buf));if ( (write(fd, buf, strlen(buf)) ) 0 ) {printf(write failed\n);return -1;}close(fd);fd -1;return 0;
}
testmychar_blockread.c
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include string.h
#include sys/ioctl.h#include mychar.h
int main(int argc, char *argv[])
{int fd -1;char buf[32] ;int ret 0;if(argc 2) {printf(The argument is too few\n);return -1;}fd open(argv[1], O_RDWR);if(fd 0) {perror(open);return -1;}if ( (read(fd, buf, sizeof(buf)) ) 0 ) {printf(read failed\n);return -1;} else {printf(buf %s\n, buf);}close(fd);fd -1;return 0;
}
运行结果