上海有色金属门户网站,如何开淘宝店,ota平台网站建设,河北先进网站建设风格一、IO多路复用--epoll实现
1.核心#xff1a;
红黑树、一张表以及三个接口、
2.实现过程及API
1#xff09;创建epoll句柄/创建红黑树根节点
int epfdepoll_create(int size--无意义#xff0c;0即可)----------成功#xff1a;返回根节点对应文件描述符#xf…一、IO多路复用--epoll实现
1.核心
红黑树、一张表以及三个接口、
2.实现过程及API
1创建epoll句柄/创建红黑树根节点
int epfdepoll_create(int size--无意义0即可)----------成功返回根节点对应文件描述符失败-1
2将要监测的文件描述符挂载到红黑树上
a.struct epoll_event event;定义事件结构体
b.struct epoll_event events[10];定义存放就绪事件描述符的数组
c.添加准备就绪事件进入epoll如
event.events EPOLLIN; // 读事件
event.data.fd fd1;
epoll_ctl(epfd, EPOLL_CTL_ADD---控制方法, fd1, event 3监听事件是否发生阻塞等待准备好的文件描述符
epoll_wait(epfd, events, 10, -1--不关心是否超时);
返回值
0:准备好的文件描述符的个数
0超时
0:失败
4)遍历数组做事件的处理 二、信号驱动IO
异步IO方式linux预留了一个信号SIGIO用于进行信号驱动IO当硬件数据准备就绪后会发起一个硬件中断在中断的处理函数中向当前进程发送一个SIGIO信号。进程收到SIGIO信号后执行信号处理函数在信号处理函数中将数据读走即可。
1.实现过程及API
应用程序
1打开设备文件
2注册信号的信号处理函数--signal(SIGIO,信号处理函数)
3回调驱动中的fasync方法完成发送信号之前的准备工作 a.获取文件描述符属性 int flagsfcntl(fd,F_GETFL); b.在文件描述符表的flags中添加FASYNC fcntl(fd,F_SETFL,flags|FASYNC); c.设置fd对应的驱动程序发送SIGIO信号只发送给当前进程 fcntl(fd,F_SETOWN,getpid());
4注意不能让主程序结束
驱动程序
1定义一个异步对象指针 struct fasync_struct *fp;
2异步操作方法 int mycdev_fasync(int fd, struct file *file, int on) // 异步操作方法
{ // 完成发送信号之前的准备工作 fasync_helper(fd, file, on, fp); return 0;
}
需要在操作方法结构体对象中加 .fasync mycdev_fasync,
3向进程发送信号 参数 fp:异步对象的二级指针 sig:要发生的信号 SIGIO band:发送信号时添加的事件标志 POLL_IN表述读数据操作
//发送信号
kill_fasync(fp,SIGIO,POLL_IN);
三、设备树
1.概念
1设备树(DeviceTree/DT/of)是用来保存设备信息的一种树形结构
2设备树的源码是独立于linux内核源码存在的
3设备树上的设备信息在内核启动后被内核解析加载到内核空间
4设备树上的节点包含属性和子节点保存设备的设备信息设备的信息由多个属性以链表形式存在属性是键值对共同描述. 2.引入设备树的原因 为了让驱动可以兼容更多硬件不在驱动中指定设备信息让驱动中获取设备树上的设备信息基于这些设备信息完成硬件的控制
设备树linux官方手册Device Tree Usage - eLinux.org
3.设备树节点结构体struct device_node和属性结构体 struct property 4.设备树节点解析API
1根据设备树节点的名字解析指定的设备树节点信息 struct device_node *dnode;
dnodeof_find_node_by_name(NULL默认从根节点解析,mynode);
返回值成功返回目标节点首地址失败返回NULL
测试
printk(name%s,value%s\n,dnode-properties-name,(char *)dnode-properties-value);
2)根据设备树节点路径解析设备树节点信息 3)根据节点的厂商信息解析指定的节点 dnodeof_find_compatible_node(NULL默认从根节点解析,NULL(设备类型),:compatible值);
4将大端字节序32位的数据转换成主机字节序
__u32 __be32_to_cpup(const __be32 *p)
printk(name%s,value%x %x\n,dnode-properties-next-next-name, __be32_to_cpup((u32 *)dnode-properties-next-next-value), __be32_to_cpup((u32 *)dnode-properties-next-next-value1));
5.属性解析API 返回值成功返回属性对象指针失败返回NULL
struct property *pr;
int len;
prof_find_property(dnode,uint,len);
测试
printk(name%s value%x %x\n,pr-name,__be32_to_cpup((u32 *)pr-value), __be32_to_cpup((u32 *)pr-value1)); epoll实现IO多路复用的应用程序
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
#include stdlib.h
#include string.h
#include sys/wait.h
#include sys/ioctl.h
#include sys/select.h
#include sys/epoll.h
/* According to earlier standards */
#include sys/time.hint main(int argc, char const *argv[])
{int fd1, fd2, epfd;struct epoll_event event; // 用于操作epollstruct epoll_event events[10]; // 存放就绪事件描述符的数组char buf[128] {0};// 创建epoll句柄epfd epoll_create(1);if (epfd 0){printf(epoll_create filed\n);exit(-1);}// 打开设备文件fd1 open(/dev/input/mouse0, O_RDWR);if (fd1 0){printf(打开鼠标设备文件失败\n);exit(-1);}fd2 open(/dev/mycdev0, O_RDWR);if (fd2 0){printf(打开鼠标设备文件失败\n);exit(-1);}// 添加准备就绪事件进入epoll;event.events EPOLLIN; // 读事件event.data.fd fd1;if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd1, event) 0){printf(epoll_ctl add filed\n);}event.events EPOLLIN; // 读事件event.data.fd fd2;if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd2, event) 0){printf(epoll_ctl add filed\n);}// 监听事件是否发生while (1){// 如果成功ret接收返回的事件个数把就绪的事件放在events数组中int ret epoll_wait(epfd, events, 10, -1);if (ret 0){printf(epoll_wait filed\n);exit(-1);}int i;// 循环遍历数组做事件的处理for (i 0; i ret; i){if (events[i].events EPOLLIN)//判断发生的事件是不是读事件{read(events[i].data.fd, buf, sizeof(buf));printf(buf:%s\n, buf);}}}close(fd1);close(fd2);return 0;
}
信号驱动IO
proc1.c
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
#include stdlib.h
#include string.h
#include sys/wait.h
#include sys/ioctl.h
#include sys/select.h
#include sys/epoll.h
/* According to earlier standards */
#include sys/time.h
int fd; // 存放就绪事件描述符的数组
char buf[128] {0};
// 定义信号处理函数
void sigio_handler(int sig)
{read(fd, buf, sizeof(buf));printf(buf:%s\n, buf);
}
int main(int argc, char const *argv[])
{// 打开设备文件fd open(/dev/myled0, O_RDWR);if (fd 0){printf(打开设备文件失败\n);exit(-1);}// 注册SIGIO信号的信号处理函数signal(SIGIO, sigio_handler);// 回调驱动中的fasync方法完成发送信号之前的准备工作int flags fcntl(fd,F_GETFL); // 获取文件描述符属性fcntl(fd,F_SETFL,flags|FASYNC); // 在文件描述符表的flags中添加FASYNC就可以回调fasync方法fcntl(fd,F_SETOWN,getpid());//驱动发送信号只发送给当前进程while(1){printf(aaaaa\n);sleep(1);}close(fd);return 0;
}proc2.c
#include stdlib.h
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
#include string.h
#include sys/ioctl.hint main(int argc, char const *argv[])
{char buf[128] hello world;int fd open(/dev/myled0, O_RDWR);if (fd 0){printf(打开设备文件失败\n);exit(-1);}write(fd, buf, sizeof(buf));close(fd);return 0;
}fasync.c
#include linux/init.h
#include linux/module.h
#include linux/cdev.h
#include linux/fs.h
#include linux/device.h
#include linux/uaccess.h
#include linux/slab.h
#include linux/wait.h
#include linux/poll.h
struct cdev *cdev;
char kbuf[128] {0};
unsigned int major 0;
unsigned int minor 0;
dev_t devno;
module_param(major, uint, 0664); // 方便在命令行传递major的值
struct class *cls;
struct device *dev;
struct fasync_struct *fp; // 定义一个异步对象指针// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{printk(%s:%s:%d\n, __FILE__, __func__, __LINE__);return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{int ret;// 判断IO方式if (file-f_flags O_NONBLOCK) // 非阻塞{}else // 阻塞{}ret copy_to_user(ubuf, kbuf, size);if (ret){printk(copy_to_user err\n);return -EIO;}return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{int ret;// 从用户拷贝数据模拟硬件数据ret copy_from_user(kbuf, ubuf, size);if (ret){printk(copy_from_user err\n);return -EIO;}//发送信号异步对象二级指针要发生的信号发送信号时添加事件的标志位kill_fasync(fp,SIGIO,POLL_IN);return 0;
}int mycdev_fasync(int fd, struct file *file, int on) // 异步操作方法
{// 完成发送信号之前的准备工作fasync_helper(fd, file, on, fp);return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{printk(%s:%s:%d\n, __FILE__, __func__, __LINE__);return 0;
}
// 定义一个操作方法结构体对象并且初始化
struct file_operations fops {.open mycdev_open,.read mycdev_read,.write mycdev_write,.fasync mycdev_fasync,.release mycdev_close,
};
static int __init mycdev_init(void)
{int ret;// 为字符设备驱动对象申请空间cdev cdev_alloc();if (cdev NULL){printk(字符设备驱动对象申请空间失败\n);ret -EFAULT;goto out1;}printk(申请对象空间成功\n);// 初始化字符设备驱动对象cdev_init(cdev, fops);// 申请设备号if (major 0) // 静态指定设备号{ret register_chrdev_region(MKDEV(major, minor), 3, myled);if (ret){printk(静态申请设备号失败\n);goto out2;}}else if (major 0) // 动态申请设备号{ret alloc_chrdev_region(devno, minor, 3, myled);if (ret){printk(动态申请设备号失败\n);goto out2;}major MAJOR(devno); // 获取主设备号minor MINOR(devno); // 获取次设备号}printk(申请设备号成功\n);// 注册字符设备驱动对象ret cdev_add(cdev, MKDEV(major, minor), 3);if (ret){printk(注册字符设备驱动对象失败\n);goto out3;}printk(注册字符设备驱动对象成功\n);// 向上提交目录信息cls class_create(THIS_MODULE, myled);if (IS_ERR(cls)){printk(向上提交目录失败\n);ret -PTR_ERR(cls);goto out4;}printk(向上提交目录成功\n);// 向上提交设备节点信息int i;for (i 0; i 3; i){dev device_create(cls, NULL, MKDEV(major, i), NULL, myled%d, i);if (IS_ERR(dev)){printk(向上提交设备节点信息失败\n);ret -PTR_ERR(dev);goto out5;}}printk(向上提交设备信息成功\n);return 0;
out5:// 释放前一次提交成功的设备信息for (--i; i 0; i--){device_destroy(cls, MKDEV(major, i));}class_destroy(cls); // 释放目录
out4:cdev_del(cdev);
out3:unregister_chrdev_region(MKDEV(major, minor), 3);
out2:kfree(cdev);
out1:return ret;
}
static void __exit mycdev_exit(void)
{// 释放节点信息int i;for (i 0; i 3; i){device_destroy(cls, MKDEV(major, i));}// 销毁目录class_destroy(cls);// 注销驱动对象cdev_del(cdev);// 释放设备号unregister_chrdev_region(MKDEV(major, minor), 3);// 释放对象空间kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE(GPL);