当前位置: 首页 > news >正文

win2012做网站创新的天津网站建设

win2012做网站,创新的天津网站建设,制作网站协议,大型网站技术方案一、IO模型 I/O 模型在操作系统中用于处理应用程序与设备驱动之间的数据传输。I/O 通信模型的核心是解决程序与设备之间如何高效、合理地进行数据通信。不同的模型通过阻塞、非阻塞、同步、异步的方式来控制数据流和处理 I/O 请求。 注#xff1a;在驱动开发中可以定义一个全…一、IO模型 I/O 模型在操作系统中用于处理应用程序与设备驱动之间的数据传输。I/O 通信模型的核心是解决程序与设备之间如何高效、合理地进行数据通信。不同的模型通过阻塞、非阻塞、同步、异步的方式来控制数据流和处理 I/O 请求。 注在驱动开发中可以定义一个全局结构体 用于全局管理驱动程序的状态和资源。在驱动开发中有时需要一个全局的数据结构来保存设备的状态、驱动配置、缓存、锁等信息这样不同的驱动程序函数可以通过该结构体访问和修改共享的资源。作用 统一管理驱动状态: 全局结构体通常保存驱动程序的各种状态信息。例如设备的注册信息、分配的内存、硬件寄存器映射等都可以保存在这个结构体中。共享资源: 驱动程序通常会有多个函数被内核调用比如初始化函数、读写函数、中断处理函数等。使用全局结构体可以让这些函数方便地共享和访问同样的数据或资源。简化代码结构: 将驱动程序涉及的所有全局变量封装在一个结构体中使代码更加清晰、结构化同时也减少了全局变量命名冲突的可能性。 一、阻塞 I/O 模型 阻塞 I/O 是最常见的 I/O 模型。当应用程序发起 I/O 请求时如果数据没有准备好应用程序将进入阻塞状态等待数据准备完毕后驱动程序会唤醒阻塞的应用程序。此时应用程序才能继续执行。工作流程 应用程序向驱动发送读取数据的请求。 如果驱动程序中数据尚未准备好应用程序进入 睡眠状态等待数据到来。 当数据准备好后驱动程序会唤醒应用程序程序从睡眠状态恢复继续读取数据。 完成 I/O 操作后应用程序继续执行其他任务。具体步骤 a. 定义并初始化等待队列 wait_queue_head_t wqhead;//在全局结构体中 在结构体 global_struct 中定义了 wqhead表示等待队列头用于管理睡眠进程的队列。在mod_init() 初始化函数中通过 init_waitqueue_head() 初始化等待队列头。 init_waitqueue_head(gstruct.wqhead);b. 进程睡眠机制 在 chdev_read 函数中当应用程序尝试从驱动读取数据时程序会检查数据是否可用。如果数据不可用进程就会进入睡眠状态挂到等待队列上。 wait_event_interruptible(pt_gstruct-wqhead, pt_gstruct-data_flag); c. 唤醒机制 当数据到达时会通过 chdev_write 函数进行处理 pt_gstruct-data_flag 1;//数据写入后data_flag 被设置为 1表示数据已准备好。 wake_up_interruptible(pt_gstruct-wqhead); wake_up_interruptible() 函数用于唤醒等待队列 wqhead 上的所有进程唤醒后之前处于睡眠状态的进程会继续执行 chdev_read 函数中的代码读取数据。二、非阻塞I/O实现 非阻塞 I/O 的实现逻辑与阻塞 I/O 类似但不进入睡眠状态。如果数据尚未准备好非阻塞 I/O 立即返回错误 -EAGAIN告诉应用程序稍后重试。 if (file-f_flags O_NONBLOCK) { // 检查文件标志是否为非阻塞模式if (pt_gstruct-data_flag 0) // 没有数据可用return -EAGAIN; // 返回 EAGAIN 错误表示无数据稍后重试 } 三、异步通知 异步通知Asynchronous Notification是 Linux 内核提供的一种机制它允许设备驱动在数据准备好或状态发生变化时主动向应用程序发送信号通常是 SIGIO 信号通知应用程序及时处理。这种机制在应用程序不需要不断轮询设备状态的情况下非常有用。设备驱动中的结构定义 struct global_struct {struct class *cls;int major, minor;struct cdev cdev_obj;wait_queue_head_t wqhead; // 等待队列头char sharebuf[128]; // 共享缓冲区int data_flag; // 标记数据是否可用0 表示无数据1 表示有数据struct fasync_struct *fapp; // 异步通知结构用于管理异步通知 }; 驱动程序的 fasync 实现 int chdev_fasync(int fd, struct file *file, int on) {struct global_struct *pt_gstruct file-private_data;// fasync_helper 负责将文件描述符和进程与异步通知关联或解除关联return fasync_helper(fd, file, on, pt_gstruct-fapp); } 实现数据写入时的异步通知 //当驱动程序中有新数据时通过 kill_fasync 向注册了异步通知的进程发送信号。 ssize_t chdev_write(struct file *file, const char __user *usr, size_t sz, loff_t *loff) {struct global_struct *pt_gstruct file-private_data;long ret;// 将用户数据复制到共享缓冲区ret copy_from_user(pt_gstruct-sharebuf, usr, sz);if (ret 0) {printk(%s-%d copy_from_user err\n, __func__, __LINE__);return -3;}// 数据写入完成后标记数据已经准备好pt_gstruct-data_flag 1;// 唤醒所有等待在等待队列上的进程wake_up_interruptible(pt_gstruct-wqhead);// 发送异步通知信号通知应用程序有数据可读kill_fasync(pt_gstruct-fapp, SIGIO, POLL_IN);return sz; } 二、内核中断驱动 Linux 内核中的中断处理系统使得硬件能够通知内核发生了特定事件如数据就绪、设备完成某项任务等并让内核采取相应的处理措施。 1. 内核中获取中断号 在 ARM 等嵌入式平台上设备通常使用设备树Device Tree来描述硬件信息。驱动程序可以从设备树节点中获取与设备相关的中断号。 直接写入 device_node {compatible mydevice;reg 0x12340000 0x1000;interrupts 30 2; // 中断号 30触发类型 2下降沿触发 };设备树描述了硬件信息并提供给内核使用。在编译设备树时我们使用交叉编译工具和特定的架构。 make dtbs ARCHarm CROSS_COMPILEarm-none-linux-gnueabi- - 拷贝到共享目录 编译完成的 .dtb 文件需要通过某种方式传输到开发板。通常我们会将 .dtb 文件拷贝到一个共享目录如 NFS、TFTP 或本地磁盘以便通过 U-Boot 加载和烧录。cp arch/arm/boot/dts/your_device.dtb /path/to/shared/directory/ - 通过 U-Boot 烧录设备树文件loady 41000000- movi write dtb 命令将 .dtb 文件写入设备存储- 验证设备树文件是否生效- 重启linux,在 /proc/device-tree/ 目录会有你的 节点文件目录实现代码 of_find_node_by_path(“/key2”); // 从设备树中查找路径为 /key2 的节点irq_of_parse_and_map(of_node, 0); // 从设备节点获取中断号具体代码 // Linux 内核中断驱动程序 #include linux/kernel.h #include linux/module.h #include linux/irqreturn.h #include linux/of.h #include linux/interrupt.h #include linux/of_irq.h/* 定义全局结构体 */ struct global_struct {int irqno; // 保存从设备树中解析出的中断号int xxx; // 其他私有数据用户可以根据需要扩展 };/* 定义全局变量 */ struct global_struct gstruct;/* 中断处理函数 */ irqreturn_t irq_key_handle(int irqno, void *args) {struct global_struct *pt_gstruct args; // 从传入的参数中获取私有数据printk(KERN_INFO %s - 中断发生irqno %d, 设备中断号 %d\n, __func__, irqno, pt_gstruct-irqno);// 执行中断处理逻辑例如读取硬件状态、清除中断标志等return IRQ_HANDLED; // 返回 IRQ_HANDLED 表示中断已处理完成 }/* 模块初始化函数 */ int mod_init(void) {int ret;int irqno;struct device_node *of_node;printk(KERN_INFO 中断驱动模块初始化\n);/* 1. 通过设备树路径查找设备节点 */of_node of_find_node_by_path(/key2); // 从设备树中查找路径为 /key2 的节点if (!of_node) {printk(KERN_ERR %s - 无法找到设备树节点 /key2\n, __func__);return -EINVAL; // 返回错误码}/* 2. 从设备树节点解析中断号 */irqno irq_of_parse_and_map(of_node, 0); // 从设备节点获取中断号if (irqno 0) {printk(KERN_ERR %s - 无法从设备树节点中解析中断号\n, __func__);return -EINVAL; // 返回错误码}printk(KERN_INFO %s - 获取的中断号为 %d\n, __func__, irqno);/* 3. 保存中断号到全局结构体中 */gstruct.irqno irqno;gstruct.xxx 10086; // 示例私有数据/* 4. 注册中断处理程序 */ret request_irq(irqno, irq_key_handle, IRQF_TRIGGER_FALLING, key2_intr, gstruct);if (ret 0) {printk(KERN_ERR %s - 注册中断处理程序失败错误码%d\n, __func__, ret);return ret; // 返回错误码}printk(KERN_INFO 中断处理程序注册成功中断号为 %d\n, irqno);return 0; // 模块初始化成功 }/* 模块退出函数 */ void mod_exit(void) {/* 释放中断 */free_irq(gstruct.irqno, gstruct); // 释放之前注册的中断printk(KERN_INFO 中断驱动模块卸载\n); }/* 声明模块的初始化和退出函数 */ module_init(mod_init); module_exit(mod_exit);/* 模块的许可信息 */ MODULE_LICENSE(GPL); MODULE_AUTHOR(Your Name); MODULE_DESCRIPTION(Simple IRQ Device Driver using Device Tree); MODULE_VERSION(1.0); 简明步骤 编写设备树节点在设备树.dts 文件中定义设备的中断号和触发类型。 在设备树.dts 文件中定义设备的中断号和触发类型。 key2: gpio-keys {compatible gpio-keys;interrupts 30 IRQ_TYPE_EDGE_FALLING; // 中断号 30下降沿触发 }; 编写中断驱动程序 定义驱动的全局结构体保存中断号和其他私有数据。实现中断处理函数。 irqreturn_t irq_key_handle(int irqno, void *args) {printk(KERN_INFO 中断发生irqno %d\n, irqno);return IRQ_HANDLED; } 从设备树获取中断号 使用 of_find_node_by_path(“/key2”) 查找设备树节点。使用 irq_of_parse_and_map() 解析设备树中的中断号。 struct device_node *of_node of_find_node_by_path(/key2); int irqno irq_of_parse_and_map(of_node, 0);注册中断处理程序使用 request_irq() 函数注册中断处理函数。 request_irq(irqno, irq_key_handle, IRQF_TRIGGER_FALLING, key2_intr, gstruct); 释放中断资源在模块退出时在 mod_exit 函数中使用 free_irq() 释放中断资源。 free_irq(gstruct.irqno, gstruct); 编译并加载内核模块编译驱动模块并加载到内核中验证中断是否正常工作。 中断下半部分 在 Linux 内核中中断处理分为上半部分和下半部分。上半部分Top Half是中断处理函数ISRInterrupt Service Routine它在中断发生时立即执行尽量简短以提高系统响应速度。为了避免在中断上下文中执行复杂或耗时的操作Linux 提供了下半部分Bottom Half机制用于延迟处理不需要立即执行的任务。LINUX系统中执行单元具体分别如下 执行单元优先级是否允许睡眠适合任务类型进程低可以睡眠耗时或不耗时任务不紧急任务中断下半部分中否耗时任务紧急任务中断上半部分高否禁止睡眠短时间任务不耗时紧急任务 中断下半部分机制 中断下半部分机制优先级是否允许睡眠适用场景使用方式软中断很高否内核专用处理大量事件内核开发者使用驱动开发者不使用Tasklet中等否驱动开发中常用处理短任务1. 定义并初始化 Tasklet 对象2. 在中断上半部分中调度 Tasklet工作队列低是处理复杂、长时间或阻塞任务1. 定义并初始化 Workqueue 对象2. 在中断上半部分中调度 Workqueue Tasklet的使用方法 定义tasklet_struct用于管理和定义Tasklet struct tasklet_struct {void (*func)(unsigned long data); // Tasklet 的处理函数unsigned long data; // 传递给处理函数的私有数据 };初始化Tasklet_struct tasklet_init() 函数用于初始化 tasklet_struct 结构体指定 Tasklet 的处理函数和私有数据。 void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); 调度Tasklet tasklet_schedule() 用于调度 Tasklet告诉内核这个 Tasklet 需要执行。tasklet_schedule() 实际上不会立即执行 Tasklet而是将 Tasklet 标记为可执行的。当中断处理完成后内核会检测到 Tasklet 已经被调度会在稍后的软中断上下文中执行 Tasklet。 void tasklet_schedule(struct tasklet_struct *t);注意事项 tasklet_kill()在模块卸载时需要调用 tasklet_kill()它会确保 Tasklet 完成后才退出以免在卸载模块时 Tasklet 仍在执行。软中断上下文Tasklet 是在软中断上下文中执行的因此不能进行睡眠操作也不能执行阻塞的 I/O 操作。 具体代码 #include linux/module.h #include linux/kernel.h #include linux/interrupt.h// Tasklet 处理函数 void my_tasklet_func(unsigned long data) {printk(KERN_INFO Tasklet 执行数据: %lu\n, data); }// 定义 Tasklet 对象 struct tasklet_struct my_tasklet;irqreturn_t irq_handler(int irq, void *dev_id) {printk(KERN_INFO 中断发生调度 Tasklet\n);// 调度 Tasklet 执行tasklet_schedule(my_tasklet);return IRQ_HANDLED; }static int __init my_init(void) {int irq 19; // 假设使用中断号 19// 初始化 Tasklet传递处理函数和私有数据tasklet_init(my_tasklet, my_tasklet_func, 100);// 注册中断处理程序if (request_irq(irq, irq_handler, IRQF_SHARED, my_tasklet_device, NULL)) {printk(KERN_ERR 无法注册中断处理程序\n);return -1;}printk(KERN_INFO 模块加载成功Tasklet 初始化完成\n);return 0; }static void __exit my_exit(void) {// 杀掉 Tasklet 确保它已经完成tasklet_kill(my_tasklet);// 释放中断free_irq(19, NULL);printk(KERN_INFO 模块卸载Tasklet 资源已释放\n); }module_init(my_init); module_exit(my_exit);MODULE_LICENSE(GPL); MODULE_AUTHOR(Your Name); MODULE_DESCRIPTION(Tasklet 示例); 工作队列的使用方法 工作队列Workqueue是 Linux 内核中提供的一种机制用于将任务推迟到进程上下文中执行。与 Tasklet 和软中断不同工作队列允许进行阻塞操作和睡眠因此适用于处理更为复杂、耗时的任务如文件 I/O 或长时间的计算任务。工作队列是在内核线程中执行的运行环境与普通内核线程一致能够进行各种内核操作。 具体代码 定义工作队列 工作队列通过 struct work_struct 定义 struct work_struct workqueue_obj;初始化工作队列 在模块初始化时使用 INIT_WORK() 初始化工作队列对象并关联任务函数 workqueue_handle INIT_WORK(gstruct.workqueue_obj, workqueue_handle); 调度工作队列 在中断处理函数的下半部分 tasklet_fun 中通过 schedule_work() 来调度工作队列 schedule_work(gstruct.workqueue_obj); 工作队列处理函数 工作队列函数 workqueue_handle 是实际执行任务的地方它运行在内核线程上下文中因此可以执行阻塞操作 void workqueue_handle(struct work_struct *work) {struct global_struct *pt_gstruct container_of(work, struct global_struct, workqueue_obj);/* 中断产生数据 */pt_gstruct-keycnt;sprintf(pt_gstruct-sharebuf, hello usrread, keycnt%d, pt_gstruct-keycnt);/* 唤醒等待队列通知有数据可读 */pt_gstruct-data_flag 1;wake_up_interruptible(pt_gstruct-wqhead);/* 发送信号给用户进程通知数据到达 */kill_fasync(pt_gstruct-fapp, SIGIO, POLL_IN);printk(%s-%d irqno%d\n, __func__, __LINE__, pt_gstruct-irqno); } 模块退出时的清理 在模块卸载时需要确保工作队列中的任务已完成或取消避免在模块卸载后还有未完成的任务 cancel_work_sync(gstruct.workqueue_obj); 代码示例 #include linux/module.h #include linux/kernel.h #include linux/interrupt.h #include linux/workqueue.h #include linux/gpio.h/* 假设 GPIO 中断号为 17 */ #define GPIO_IRQ_NUM 17/* 全局工作队列对象 */ static struct work_struct my_workqueue;/* 工作队列处理函数 */ void workqueue_func(struct work_struct *work) {printk(KERN_INFO 工作队列任务执行处理复杂的任务\n);/* 模拟耗时操作 */msleep(2000); // 模拟阻塞操作printk(KERN_INFO 工作队列任务完成\n); }/* 中断处理程序上半部分 */ irqreturn_t irq_handler(int irq, void *dev_id) {printk(KERN_INFO 中断触发调度工作队列\n);/* 调度工作队列 */schedule_work(my_workqueue);return IRQ_HANDLED; }/* 模块初始化 */ static int __init my_module_init(void) {int ret;/* 初始化工作队列 */INIT_WORK(my_workqueue, workqueue_func);/* 注册中断处理程序 */ret request_irq(GPIO_IRQ_NUM, irq_handler, IRQF_SHARED, my_workqueue_device, my_workqueue);if (ret) {printk(KERN_ERR 无法注册中断处理程序\n);return ret;}printk(KERN_INFO 工作队列模块已加载\n);return 0; }/* 模块卸载 */ static void __exit my_module_exit(void) {/* 确保工作队列任务已完成或被取消 */cancel_work_sync(my_workqueue);/* 释放中断 */free_irq(GPIO_IRQ_NUM, my_workqueue);printk(KERN_INFO 工作队列模块已卸载\n); }/* 模块入口和出口 */ module_init(my_module_init); module_exit(my_module_exit);MODULE_LICENSE(GPL); MODULE_AUTHOR(Your Name); MODULE_DESCRIPTION(工作队列使用示例);
http://www.ho-use.cn/article/10817954.html

相关文章:

  • 网站使用说明书模板wordpress文章页插件
  • 建湖做网站多少钱游戏网站设计风格有哪些
  • 医院网站源码下载互联网开发软件
  • 网站开发配置表格火车头wordpress 4.7
  • 黑群晖建设个人网站wordpress上传不了图片
  • 商标设计网站排行百姓装潢上海门店具体地址
  • 淘宝客怎么样做自己的网站腾讯cdn WordPress
  • 网站建设吉金手指排名14微软 开源 wordpress
  • 代刷网站开发wordpress文章列表加广告
  • 如何做社团网站怎么引流推广
  • 在外国租服务器做那种网站中国做的最好的网站建设公司
  • wordpress适合外贸站网站怎么做qq微信登陆界面设计
  • 制作好网站饮食网站模板
  • 在深圳学网站设计广水做网站
  • 关键词分析工具网站怎么知道网站的域名
  • 怎么做查询网站后台家居品牌网站建设
  • 公司网站改版方案盛世网站建站流程
  • 罗琳做的网站软装公司
  • net大规模网站开发视频wordpress制作
  • 国家住房和城乡建设厅网站企业网站制作 厦门
  • 怎么搞一个网站平台四川建设考试培训网
  • wordpress查询次数太多北京网站优化什么价格
  • 怎样使用网站模板给别人做网站是外包公司
  • 购物型网站怎么建立必应搜索引擎下载
  • 建设网站便宜微网站免费搭建平台
  • 网站使用授权书永久免费的crm软件
  • 做网站的规范尺寸河北最近发生了什么事
  • 做网站需要空间口碑好的网站建设加工
  • 营销型网站建设要多少钱网站投放广告怎么做
  • 设计师做画册必备网站做标识的网站 知乎