本章的目的是让读者知道:
1.内核与用户空间同步
2.如何使进程休眠(并唤醒)
3.如何实现非阻塞I/O
4.设备可读取或写入时如何通知用户空间
#include <linux/ioctl.h>
这个头文件声明了用于定义ioctl命令的所有的宏。它现在包含在<linux/fs.h>中。
_IOC_NRBITS
_IOC_TYPEBITS
_IOC_SIZEBITS
_IOC_DIRBITS
ioctl命令的不同位字段的可用位数。还有四个宏定义了不同的MASK(掩码),另外四个宏定义了不同的SHIFT(偏移),但它们基本上仅在内部使用。由于_IOC_SIZEBITS在不同体系架构上的值不同,因此需要重点关注。
_IOC_NONE
_IOC_READ
_IOC_WRITE
“方向”位字段的可能值。“读”和“写”是不同的位,可以“OR”在一起来指定读/写。这些值都是基于0的。
_IOC(dir,type,nr,size)
_IO(type,nr)
_IOC(type,nr,size)
_IOW(type,nr,size)
_IOWR(type,nr,size)
用于生成ioctl命令的宏。
_IOC_DIR(nr)
_IOC_TYPE(nr)
_IOC_NR(nr)
_IOC_SIZE(nr)
用于解码ioctl命令的宏。特别地,_IOC_TYPE(nr)是_IOC_READ和_IOC_WRITE进行“OR”的结果。
#include <asm/uaccess.h>
int access_ok(int type,const void *addr,unsigned long size);
这个函数验证指向用户空间的指针是否可用。如果允许访问,access_ok返回非零值。
VERIFY_READ
VERIFY_WRITE
在access_ok中type参数可取的值。VERIFY_WRITE是VERIFY_READ的超集。
#include <asm/uaccess.h>
int put_user(datum,ptr);
int get_user(local,ptr);
int __put_user(datum,ptr);
int __get_user(local,ptr);
用于向(或从)用户空间保存(或获取)单个数据项的宏。传递的字节数目由sizeof(*ptr)决定。前两个要先调用access_ok,后两个(__put_user和__get_user)则假设access_ok已经被调用过了。
#include <linux/capability.h>
定义有各种CAP_符号,用于描述用户空间进程可能拥有的权能操作。
int capable(int capability);
如果进程具有指定的权能,返回非零值。
#include <linux/wait.h>
typedef struct {/* ... */} wait_queue_head_t;
void init_waitqueue_head(wait_queue_head_t *queue);
DECLARE_WAIT_QUEUE_HEAD(queue);
预先定义的Linux等待队列类型。wait_queue_head_t类型必须显式地初始化,初始化方法可在运行时用init_waitqueue_head,或在编译时用DECLARE_WAIT_QUEUE_HEAD。
void wait_event(wait_queue_head_t q,int condition);
int wait_event_interruptible(wait_queue_head_t q,int condition);
int wait_event_timeout(wait_queue_head_t q,int condition,int time);
int wait_event_interruptible_timeout(wait_queue_head_t q,int condition,int time);
使进程在指定的队列上休眠,直到给定的condition值为真。
void wake_up(struct wait_queue **q);
void wakr_up_interruptible(struct wait_queue **q);
void wake_up_nr(struct wait_queue **q,int nr);
void wake_up_interruptible_nr(struct wait_queue **q,int nr);
void wake_up_all(struct wait_queue **q);
void wake_up_interruptible_all(struct wait_queue **q);
void wake_up_interruptible_sync(struct wait_queue **q);
这些函数唤醒休眠在队列q上的进程。_interruptible形式的函数只能唤醒可中断的进程。通常,只会唤醒一个独占等待进程,但其行为通过_nr或_all形式改变。_sync版本的唤醒函数在返回前不会重新调度CPU。
#include <linux/sched.h>
set_current_state(int state);
设置当前进程的执行状态。TASK_RUNNING表示准备运行,而休眠状态是TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE。
void schedule(void);
从运行队列中选择一个可运行进程,选定的进程可以是current或另一个不同的进程。
typedef struct {/* ... */} wait_queue_t;
init_waitqueue_entry(wait_queue_t *entry,struct task_strcut *task);
wait_queue_t类型用来将某个进程放置到一个等待队列上。
void prepare_to_wait(wait_queue_head_t *queue,wait_queue_t *wait,int state);
void prepare_to_wait_exclisive(wait_queue_head_t *queue,wait_queue_t *wait,int state);
void finish_wait(wait_queue_head_t *queue,wait_queue_t *wait);
可用于手工休眠代码的辅助函数。
void sleep_on(wait_queue_head_t *queue);
void interruptible_sleep_on(wait_queue_head_t *queue);
已废弃的两个函数,它们将当前进程无条件地置于休眠状态。
#include <linux/poll.h>
void poll_wait(struct file *filp,wait_queue_head_t *q,pool_table *p);
将当前进程置于某个等待队列但并不立即调度。该函数主要用于设备驱动程序的poll方法。
int fasync_helper(struct inode *inode,struct file *filp,int mode,struct fasync_struct **fa);
用来实现fasync设备方法的辅助函数。mode参数取传入该方法的同一值,而fa指向设备专有的fasync_struct *。
void kill_fasync(struct fasync_struct *fa,int sig,int band);
如果驱动程序支持异步通知,则这个函数可以用来发送一个信号给注册在fa中的进程。
int nonseekable_open(struct inode *inode,struct file *filp);
loff_t no_llseek(struct file *file,loff_t offset,int whence);
任何不支持定位的设备都应该在其open方法中调用nonseekable_open。这类设备还应该在其llseek方法中使用no_llseek。