继续向后面学习,接下去要看的就是阻塞和非阻塞编程。
我在书上看到这么一段程序,但我觉得好像哪里有点不对。最后看过内核源代码后才豁然开朗。
主要是down_interruptible()这个函数,网上普遍的解释如下
int down_interruptible(struct semaphore *sem) //这个函数的功能就是获得信号量,如果得不到信号量就睡眠,此时没有信号打断,那么进入睡眠。但是在睡眠过程中可能被信号打断,打断之后返回-EINTR,主要用来进程间的互斥同步。
然后我就一直在琢磨,那它在睡眠中被对应的信号量唤醒后,那它会不会执行P操作了?
一开始我还以为会执行P操作的,但是源代码中是这么写着的
/** * down_interruptible - acquire the semaphore unless interrupted * @sem: the semaphore to be acquired * * Attempts to acquire the semaphore. If no more tasks are allowed to * acquire the semaphore, calling this function will put the task to sleep. * If the sleep is interrupted by a signal, this function will return -EINTR. * If the semaphore is successfully acquired, this function returns 0. */ int down_interruptible(struct semaphore *sem) { unsigned long flags; int result = 0; spin_lock_irqsave(&sem->lock, flags); if (likely(sem->count > 0)) sem->count--; else result = __down_interruptible(sem); spin_unlock_irqrestore(&sem->lock, flags); return result; }
在这个if中可以看出,P操作只在一开始判断到可以获取信号量的时候才会执行,一开始如果信号量已经被人占用,那么就只能进入睡眠,等到睡眠醒后,依然是没有获取信号量的,除非down_interruptible()再执行一遍。这个貌似在好多down()中都是这么一个写法。
在这一章的最后,讲了字符设备驱动程序对一些高级特性的实现
驱动实现non-seekable
1)在open功能函数中调用nonseekable_open(inode,filp)告知OS本设备不支持seek
int nonseekable_open(inode,filp) { filp->f_mode &= ~(FMODE_LSEEK|FMODE_PREAD|FMODE_PWRITE); return 0; }
2)将file_operations中的.llseek设置为no_llseek。no_llseek会向操作系统返回ESPIPE
loff_t no_llseek(struct file * file,loff_t offset,int origin) { return -ESPIPE; }
驱动如何实现select
操作系统对select的实现
当用户程序调用select时,操作系统会依次轮询select中指定的所有文件描述符对应的设备,即调用所有设备驱动程序中的.poll函数
poll函数会做两件事
A)告知操作系统如果设备暂时不可用的话,进程应该阻塞在哪个等待队列上(输入还是输出)
B)根据设备的具体状况告知操作系统设备是否可用(信号量是否被占用等等)