深圳专业网站设计公司哪家好风险网站怎么解决方法
深圳专业网站设计公司哪家好,风险网站怎么解决方法,门户网站建设需注意的问题,自己做网站打开很卡1. 驱动中阻塞相关函数的基础
1.1 wait_queue_head_t
定义等待队列头 #include linux/wait.h
/** lock#xff1a;自旋锁#xff0c;用于保护队列操作#xff08;如添加/删除等待项#xff09;的并发安全* head#xff1a;链表头#xff0c;指向等待队列项的链…1. 驱动中阻塞相关函数的基础1.1 wait_queue_head_t定义等待队列头#include linux/wait.h/** lock自旋锁用于保护队列操作如添加/删除等待项的并发安全 * head链表头指向等待队列项的链表*/typedefstructwait_queue_head { spinlock_tlock;structlist_head head; } wait_queue_head_t;1.2 init_waitqueue_head初始化一个已经分配了内存的等待队列头设置其自旋锁和链表为空voidinit_waitqueue_head(wait_queue_head_t *q);1.3 DECLARE_WAITQUEUE静态声明并初始化一个等待队列项wait queue entry。该宏创建一个wait_queue_entry类型的变量并将指定的进程描述符tsk当前进程为current与该队列项关联同时设置默认的唤醒函数DECLARE_WAITQUEUE(name, tsk);//使用方式DECLARE_WAITQUEUE(wait, current);//展开后为wait_queue_entry_t wait { .private current,//指向等待的进程 task_struct.func default_wake_function,//唤醒时调用的函数.task_list { NULL, NULL }//链表节点用于挂入等待队列头};1.4 add_wait_queue将一个已经初始化好的等待队列项wait添加到等待队列头queue所管理的队列中。添加后该队列项就成为了等待队列的一部分在进程准备睡眠之前先将自己添加到等待队列这样其他唤醒者才能找到它voidadd_wait_queue(wait_queue_head_t *queue, wait_queue_t *wait);1.5 set_current_state设置当前进程的状态将current-state赋值为new_state/* by yours.tools - online tools website : yours.tools/zh/formatvbs.html */ 进程状态定义在linux/sched.h中常见的有/* by yours.tools - online tools website : yours.tools/zh/formatvbs.html */ TASK_RUNNING可运行状态正在运行或就绪。TASK_INTERRUPTIBLE可中断的睡眠状态可以被信号唤醒。TASK_UNINTERRUPTIBLE不可中断的睡眠状态只能由显式唤醒解除。voidset_current_state(intnew_state);//有内存屏障保证顺序void__set_current_state(intnew_state);//没有内存屏障1.6remove_wait_queue将之前通过add_wait_queue添加的等待队列项从等待队列中移除当进程被唤醒并重新获得 CPU 后通常需要调用此函数将自己从等待队列中删除表示不再等待该条件如果忘记移除队列项仍留在等待队列中可能导致后续不必要的唤醒或资源泄漏voidremove_wait_queue(wait_queue_head_t *queue, wait_queue_t *wait);1.7wake_up唤醒队列中所有进程包括TASK_UNINTERRUPTIBLE和TASK_INTERRUPTIBLEvoidwake_up(wait_queue_head_t *queue);唤醒等待队列queue中所有状态为TASK_INTERRUPTIBLE的进程。这些进程将被设置为TASK_RUNNING并移入运行队列等待调度器选择它们运行voidwake_up_interruptible(wait_queue_head_t *queue);2. 阻塞驱动使用例子#include linux/init.h#includelinux/errno.h#includelinux/mm.h#includelinux/sched.h#includelinux/module.h#includelinux/ioctl.h#includelinux/io.h#includelinux/fs.h#includelinux/cdev.h#includelinux/uaccess.h#includelinux/slab.h#includelinux/wait.h#defineGLOBALFIFO_SIZE 1024#defineGLOBALMEM_MAGIC M#defineMEM_CLEAR _IO(GLOBALMEM_MAGIC, 0)structglobalfifo_dev {structcdev m_cdev;/*字符设备*/unsignedintcurrent_len;/*fifo有效数据长度*/unsignedcharmem[GLOBALFIFO_SIZE];/*全局内存*/structsemaphore sem;/*并发控制信号量*/wait_queue_head_t r_wait;/*阻塞读等待队列头*/wait_queue_head_t w_wait;/*阻塞写等待队列头*/};staticintglobalfifo_major 266;//存放字符设备私有数据structglobalfifo_dev*globalfifo_devp;/*user open fd*/staticintglobalfifo_open(structinode* inode,structfile*filp) {structglobalfifo_dev*dev; dev container_of(inode-i_cdev,structglobalfifo_dev, m_cdev); filp-private_data dev;return0; }/*user release fd*/staticintglobalfifo_release(structinode* inode,structfile*filp) {return0; }/*user read fd*/staticssize_t globalfifo_read(structfile* filp,char__user* buf, size_t count, loff_t*ppos) {intret;structglobalfifo_dev* dev filp-private_data;//定义等待队列DECLARE_WAITQUEUE(wait, current); down(dev-sem);//1.将等待队列加入到等待队列头add_wait_queue(dev-r_wait, wait);//2.循环检查等待条件防止假唤醒如果唤醒后不满足条件会再次睡眠while(dev-current_len 0) {//3. 检查非阻塞模式直接返回if(filp-f_flags O_NONBLOCK) { ret -EAGAIN; up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING);returnret; }//4.改变进程状态为可中断睡眠__set_current_state(TASK_INTERRUPTIBLE); up(dev-sem);//5.调度其他进程执行真正睡眠schedule();//6.检查如果有信号到达返回上层处理错误自己的唤醒只将状态转换为TASK_RUNNING但信号到来也会做这个处理if(signal_pending(current)) { ret -ERESTARTSYS; remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING);returnret; }//被唤醒后的处理down(dev-sem); }if(count dev-current_len) count dev-current_len;if(copy_to_user(buf, dev-mem, count)) { ret -EFAULT; up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING);returnret; }else{ memcpy(dev-mem, dev-mem count, dev-current_len -count); dev-current_len -count; wake_up_interruptible(dev-w_wait);//读出数据后唤醒写进程ret count; } up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING);returnret; }/*user write fd*/staticssize_t globalfifo_write(structfile* filp,constchar__user* buf, size_t count, loff_t*ppos) {intret;structglobalfifo_dev* dev filp-private_data;//定义等待队列DECLARE_WAITQUEUE(wait, current); down(dev-sem);//1.将等待队列插入写等待队列头add_wait_queue(dev-w_wait, wait);//2.循环等待 若FIFO满则应该挂起while(dev-current_len GLOBALFIFO_SIZE) {//3. 若非阻塞则直接返回if(filp-f_flags O_NONBLOCK) { up(dev-sem); ret -EAGAIN; remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING);returnret; }//4.将进程状态改为可打断睡眠__set_current_state(TASK_INTERRUPTIBLE); up(dev-sem);//5.调度其他进程真正睡眠schedule();//6.若因为信号唤醒则返回让上层完成错误处理if(signal_pending(current)) { ret -ERESTARTSYS; remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING);returnret; } down(dev-sem); }if(count GLOBALFIFO_SIZE - dev-current_len) count GLOBALFIFO_SIZE - dev-current_len;if(copy_from_user(dev-mem, buf, count)) { ret -EFAULT; up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING);returnret; }else{ dev-current_len count;//唤醒等待队列wake_up_interruptible(dev-r_wait); retcount; } up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING);returncount; }/*user lseek fd*/staticloff_t globalfifo_llseek(structfile* filp, loff_t offset,intorig) { loff_t ret;switch(orig) {//从起始位置开始移动指针case0:if(offset 0) { ret -EINVAL;break; }if((unsignedint)offset GLOBALFIFO_SIZE) { ret -EINVAL;break; } filp-f_pos (unsignedint)offset; ret filp-f_pos;break;//从当前位置开始移动指针case1:if((filp-f_pos offset) GLOBALFIFO_SIZE) { ret -EINVAL;break; }if((filp-f_pos offset) 0) { ret -EINVAL;break; } filp-f_pos offset; ret filp-f_pos;break;default: ret -EINVAL; }returnret; }/*user ioctl fd*/staticlongglobalfifo_unlocked_ioctl(structfile *filp, unsignedintcmd, unsignedlongarg){//获取设备结构体指针structglobalfifo_dev* dev filp-private_data;switch(cmd) {caseMEM_CLEAR: down(dev-sem); dev-current_len 0; memset(dev-mem,0, GLOBALFIFO_SIZE); up(dev-sem);break;default:return-EINVAL; }return0; }staticconststructfile_operations globalfifo_fops { .ownerTHIS_MODULE, .openglobalfifo_open, .releaseglobalfifo_release, .llseekglobalfifo_llseek, .readglobalfifo_read, .writeglobalfifo_write, .unlocked_ioctlglobalfifo_unlocked_ioctl };/*设备驱动模块insmod加载函数*/staticintglobalfifo_init(void) {//向 Linux 内核中注册字符设备编号范围register_chrdev_region(MKDEV(globalfifo_major,0),1,globalfifo);//为设备以及共享内存分配内存globalfifo_devp kmalloc(sizeof(structglobalfifo_dev), GFP_KERNEL); memset(globalfifo_devp,0,sizeof(structglobalfifo_dev));//初始化字符设备0的基本字段cdev_init(globalfifo_devp-m_cdev, globalfifo_fops); globalfifo_devp-m_cdev.owner THIS_MODULE;//将主设备号globalfifo_major次设备号0与字符设备驱动的关联cdev_add(globalfifo_devp-m_cdev, MKDEV(globalfifo_major,0),1);//初始化信号量sema_init(globalfifo_devp-sem,1);//初始化读写等待队列头init_waitqueue_head(globalfifo_devp-r_wait); init_waitqueue_head(globalfifo_devp-w_wait);return0; }staticvoidglobalfifo_exit(void) { dev_t devno;//注销cdevcdev_del(globalfifo_devp-m_cdev);//释放设备结构体内存kfree(globalfifo_devp);//释放设备号devno MKDEV(globalfifo_major,0); unregister_chrdev_region(devno,1); } MODULE_AUTHOR(cear); MODULE_LICENSE(GPL); module_param(globalfifo_major,int, S_IRUGO); module_init(globalfifo_init); module_exit(globalfifo_exit);