a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 68|回复: 0

[综合辅导] Linux辅导:Linux设备驱动中非阻塞操作

[复制链接]
发表于 2012-8-4 12:07:07 | 显示全部楼层 |阅读模式
「梗阻与非梗阻界说」
- D$ S$ U/ |( M$ D梗阻操作是指,在执行设备操作时,若不能获得资本,则历程挂起直到知足可操作的前提再进行操作。被挂起的历程进入sleep 状况,被从调剂器的运行队列移走,直到期待的前提被知足。" q( N/ ^9 B8 [* ]8 |$ P
非梗阻操作的历程在不能进行设备操作时,并不挂起。
" |. _/ o1 d" d# `# B2 i: P「梗阻实例」6 v' ~4 H! V7 E9 }2 @; U
多个历程对驱动中的全局变量,有的读有的写,用梗阻机制来保证只有在某个历程写过之后,其他历程在能够读这个变量。
# e( O$ {) D7 k7 g4 |& S5 S#include 《linux/module.h》 #include 《linux/init.h》 #include 《linux/fs.h》 #include 《asm/uaccess.h》 #include 《linux/wait.h》 #include 《asm/semaphore.h》' N- o$ l8 k% R
MODULE_LICENSE(“GPL”);
6 t1 Q- r/ L1 J" r5 @#define MAJOR_NUM 2545 F/ O1 l" [9 d( {0 q  Y
static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);$ d/ ~( Q: W$ G
struct file_operations globalvar_fops = { read: globalvar_read,write: globalvar_write,};
  r3 w) Z' t. o  W$ D2 W8 ]static int global_var = 0;static struct semaphore sem;static wait_queue_head_t outq;//界说期待队列头static int flag = 0;//梗阻前提static int __init globalvar_init(void)
. Q1 q; j( s/ q' T! g# B3 }% _{ int ret;ret = register_chrdev(MAJOR_NUM, “globalvar”, &globalvar_fops);if (ret)
& `# r0 M5 D; m& X' ]# A& _0 ~. R% ~3 Z{ printk(“globalvar register failure”);} else { printk(“globalvar register success”);init_MUTEX(&sem);init_waitqueue_head(&outq);} return ret;} static void __exit globalvar_exit(void)) O2 e, a% P% P* Y+ P6 p* H
{ int ret;ret = unregister_chrdev(MAJOR_NUM, “globalvar”);if (ret)
6 J1 l5 [$ P8 w% Z2 f  i{ printk(“globalvar unregister failure”);} else { printk(“globalvar unregister success”);}
6 ^; u! c( E3 X4 h# C# o( dstatic ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
0 }5 ?4 N9 {) Y7 ^/ L  @{ //期待数据可获得if (wait_event_interruptible(outq, flag != 0))//在这里让挪用自己的历程进入挂起状况,直到满/ //足后面的前提才脱离挂起状况{ return - ERESTARTSYS;} if (down_interruptible(&sem))/ }% ^& I: Q+ L# Y. m; ~- t
{ return - ERESTARTSYS;} flag = 0; //梗阻前提在这里发生改变,意味着每次只能对这个变量读一次,除非再次给这个//变量赋了新值。
% n- Y8 K) {8 u
* v5 H: c7 d  k# H# c+ M2 i
+ L1 a. t! N# Q$ v7 V# ~0 m- Wif (copy_to_user(buf, &global_var, sizeof(int)))0 n% n; a& ?, z. s
{ up(&sem);return - EFAULT;} up(&sem);return sizeof(int);}1 B3 ]/ s% b5 s* _8 z9 L/ c0 q; A* s
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len,loff_t *off)9 C; e7 c6 S& W9 i4 D
{ if (down_interruptible(&sem))
! q% m& M) j  T5 M0 ?5 S. f- N{ return - ERESTARTSYS;} if (copy_from_user(&global_var, buf, sizeof(int)))' o: }1 V# B% N, F* [
{ up(&sem);return - EFAULT;} up(&sem);flag = 1;//梗阻前提在这里发生改变,意味着可以挂起的历程可以解禁了/*通知数据可获得前面挪用驱动read函数的历程被调整到了挂起状况,只有当知足一个前提的时辰才会从挂起状况解脱。这个处所注重了,并没有一个机制自动的检测前提,或者前提改变的时辰,自动通知内核改变历程的状况。而是,我们需要挪用函数去手动叫醒期待队列,队列会检测前提,如不美观前提知足,那么解禁历程,如不美观前提不知足,历程依然被封印。
& T. f0 u3 N) `*/ wake_up_interruptible(&outq);return sizeof(int);} module_init(globalvar_init);module_exit(globalvar_exit);! @+ e& h/ r: o) y0 Y
这里有一个问题,期待队列应该可能会有多个被封印的历程,在这种情形下:1. 后面的历程能否被前面的历程更早的解聚积1 S7 U% {; ]' M3 ]: @
2. 每次经由过程函数试图叫醒队列的时辰,队列对前提的检测机制是若何的?是否一个一个的历程挨次的检测各自的前提吗?# O' D1 V1 C' `7 k6 V7 p
用来对本驱动进行测试的参考应用轨范为:「读轨范」( _5 ^) |8 h- ]* j
#include 《sys/types.h》 #include 《sys/stat.h》 #include 《stdio.h》 #include 《fcntl.h》 main()
0 |3 e3 G& Y6 C. c9 |! B{ int fd, num;fd = open(“/dev/globalvar”, O_RDWR, S_IRUSR | S_IWUSR);if (fd != - 1)+ ~/ }# _5 D0 m6 A" k
{ while (1)
  Z' E: Y' o" L) o& ~& z{ read(fd, &num, sizeof(int)); //轨范将梗阻在此语句,除非有针对globalvar 的输入printf(“The globalvar is %d\n”, num);//如不美观输入是0,则退出if (num == 0)! e3 `# m8 z5 e( O  y4 `
{ close(fd);break;} else { printf(“device open failure\n”);}
5 N* M* @! E8 c* C) p2 {4 n「写轨范」
* U, V4 `! b9 A, y% |2 L- w: H#include 《sys/types.h》 #include 《sys/stat.h》 #include 《stdio.h》 #include 《fcntl.h》 main()( U- T5 |( e, P1 N
{ int fd, num;fd = open(“/dev/globalvar”, O_RDWR, S_IRUSR | S_IWUSR);if (fd != - 1)
* z$ V3 i0 Q8 M; `9 X  {- u% g{ while (1)
3 B% W1 H7 ~" |: l  l{ printf(“Please input the globalvar:\n”);scanf(“%d”, &num);write(fd, &num, sizeof(int));//如不美观输入0,退出if (num == 0)
" ^, H6 _# t% u, ^' V{ close(fd);break;} else { printf(“device open failure\n”);}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-21 14:21 , Processed in 0.436382 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表