struct __wait_queue_head { spinlock_t lock; struct list_head task_list; }; typedef struct __wait_queue_head wait_queue_head_t;
wait_event(queue, condition)/*不可中断休眠,不推荐*/ wait_event_interruptible(queue, condition)/*推荐,返回非零值意味着休眠被中断,且驱动应返回 -ERESTARTSYS*/ wait_event_timeout(queue, condition, timeout) wait_event_interruptible_timeout(queue, condition, timeout) /*有限的时间的休眠;若超时,则不管条件为何值返回0,*/
void wake_up(wait_queue_head_t *queue); void wake_up_interruptible(wait_queue_head_t *queue);
[Tekkaman2440@SBC2440V4]#cd /lib/modules/ [Tekkaman2440@SBC2440V4]#insmod sleepy.ko [Tekkaman2440@SBC2440V4]#cd /dev/ [Tekkaman2440@SBC2440V4]#cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 /dev/vc/0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 7 vcs 10 misc 13 input 14 sound 81 video4linux 89 i2c 90 mtd 116 alsa 128 ptm 136 pts 180 usb 189 usb_device 204 s3c2410_serial 252 sleepy 253 usb_endpoint 254 rtc Block devices: 1 ramdisk 256 rfd 7 loop 31 mtdblock 93 nftl 96 inftl 179 mmc [Tekkaman2440@SBC2440V4]#mknod -m 666 sleepy c 252 0 [Tekkaman2440@SBC2440V4]#cd /tmp/ [Tekkaman2440@SBC2440V4]#./sleepy_testr& [Tekkaman2440@SBC2440V4]#./sleepy_testr& [Tekkaman2440@SBC2440V4]#ps PID Uid VSZ Stat Command 1 root 1744 S init 2 root SW< [kthreadd] 3 root SWN [ksoftirqd/0] 4 root SW< [watchdog/0] 5 root SW< [events/0] 6 root SW< [khelper] 59 root SW< [kblockd/0] 60 root SW< [ksuspend_usbd] 63 root SW< [khubd] 65 root SW< [kseriod] 77 root SW [pdflush] 78 root SW [pdflush] 79 root SW< [kswapd0] 80 root SW< [aio/0] 707 root SW< [mtdblockd] 708 root SW< [nftld] 709 root SW< [inftld] 710 root SW< [rfdd] 742 root SW< [kpsmoused] 751 root SW< [kmmcd] 769 root SW< [rpciod/0] 778 root 1752 S -sh 779 root 1744 S init 781 root 1744 S init 783 root 1744 S init 787 root 1744 S init 799 root 1336 S ./sleepy_testr 800 root 1336 S ./sleepy_testr 802 root 1744 R ps [Tekkaman2440@SBC2440V4]#./sleepy_testw read code=0 write code=0 [2] + Done ./sleepy_testr [Tekkaman2440@SBC2440V4]#ps PID Uid VSZ Stat Command 1 root 1744 S init 2 root SW< [kthreadd] 3 root SWN [ksoftirqd/0] 4 root SW< [watchdog/0] 5 root SW< [events/0] 6 root SW< [khelper] 59 root SW< [kblockd/0] 60 root SW< [ksuspend_usbd] 63 root SW< [khubd] 65 root SW< [kseriod] 77 root SW [pdflush] 78 root SW [pdflush] 79 root SW< [kswapd0] 80 root SW< [aio/0] 707 root SW< [mtdblockd] 708 root SW< [nftld] 709 root SW< [inftld] 710 root SW< [rfdd] 742 root SW< [kpsmoused] 751 root SW< [kmmcd] 769 root SW< [rpciod/0] 778 root 1752 S -sh 779 root 1744 S init 781 root 1744 S init 783 root 1744 S init 787 root 1744 S init 799 root 1336 S ./sleepy_testr 804 root 1744 R ps [Tekkaman2440@SBC2440V4]#./sleepy_testw write code=0 [Tekkaman2440@SBC2440V4]#read code=0 [1] + Done ./sleepy_testr [Tekkaman2440@SBC2440V4]#ps PID Uid VSZ Stat Command 1 root 1744 S init 2 root SW< [kthreadd] 3 root SWN [ksoftirqd/0] 4 root SW< [watchdog/0] 5 root SW< [events/0] 6 root SW< [khelper] 59 root SW< [kblockd/0] 60 root SW< [ksuspend_usbd] 63 root SW< [khubd] 65 root SW< [kseriod] 77 root SW [pdflush] 78 root SW [pdflush] 79 root SW< [kswapd0] 80 root SW< [aio/0] 707 root SW< [mtdblockd] 708 root SW< [nftld] 709 root SW< [inftld] 710 root SW< [rfdd] 742 root SW< [kpsmoused] 751 root SW< [kmmcd] 769 root SW< [rpciod/0] 778 root 1752 S -sh 779 root 1744 S init 781 root 1744 S init 783 root 1744 S init 787 root 1744 S init 806 root 1744 R ps
while (dev->rp == dev->wp) { /* nothing to read */ up(&dev->sem); /* release the lock */ if (filp->f_flags & O_NONBLOCK) return -EAGAIN; PDEBUG("\"%s\" reading: going to sleep\n", current->comm); if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp))) return -ERESTARTSYS; /* signal: tell the fs layer to handle it */ /* otherwise loop, but first reacquire the lock */ if (down_interruptible(&dev->sem)) return -ERESTARTSYS; } /* ok, data is there, return something */ ......
void set_current_state(int new_state);
if (!condition) schedule();
/* (1)创建和初始化一个等待队列。常由宏定义完成:*/
DEFINE_WAIT(my_wait);
/*name 是等待队列入口项的名字. 也可以用2步来做:*/
wait_queue_t my_wait;
init_wait(&my_wait);
/*常用的做法是放一个 DEFINE_WAIT 在循环的顶部,来实现休眠。*/
/* (2)添加等待队列入口到队列,并设置进程状态:*/
void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state);
/*queue 和 wait 分别地是等待队列头和进程入口。state 是进程的新状态:TASK_INTERRUPTIBLE(可中断休眠,推荐)或TASK_UNINTERRUPTIBLE(不可中断休眠,不推荐)。*/
/* (3)在检查确认仍然需要休眠之后调用 schedule*/
schedule();
/* (4)schedule 返回,就到了清理时间:*/
void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait);
认真地看简单休眠中的 wait_event(queue, condition) 和 wait_event_interruptible(queue, condition) 底层源码会发现,其实他们只是手工休眠中的函数的组合。所以怕麻烦的话还是用wait_event比较好。
void prepare_to_wait_exclusive(wait_queue_head_t *queue, wait_queue_t *wait, int state);
wake_up(wait_queue_head_t *queue); wake_up_interruptible(wait_queue_head_t *queue); /*wake_up 唤醒队列中的每个非独占等待进程和一个独占等待进程。wake_up_interruptible 同样, 除了它跳过处于不可中断休眠的进程。它们在返回之前, 使一个或多个进程被唤醒、被调度(如果它们被从一个原子上下文调用, 这就不会发生).*/
wake_up_nr(wait_queue_head_t *queue, int nr); wake_up_interruptible_nr(wait_queue_head_t *queue, int nr); /*这些函数类似 wake_up, 除了它们能够唤醒多达 nr 个独占等待者, 而不只是一个. 注意传递 0 被解释为请求所有的互斥等待者都被唤醒*/
wake_up_all(wait_queue_head_t *queue);
wake_up_interruptible_all(wait_queue_head_t *queue);
/*这种 wake_up 唤醒所有的进程, 不管它们是否进行独占等待(可中断的类型仍然跳过在做不可中断等待的进程)*/
wake_up_interruptible_sync(wait_queue_head_t *queue);
/*一个被唤醒的进程可能抢占当前进程, 并且在 wake_up 返回之前被调度到处理器。 但是, 如果你需要不要被调度出处理器时,可以使用 wake_up_interruptible 的"同步"变体. 这个函数最常用在调用者首先要完成剩下的少量工作,且不希望被调度出处理器时。*/
unsigned int (*poll) (struct file *filp, poll_table *wait);
void poll_wait (struct file *, wait_queue_head_t *, poll_table *);
标志
|
含义
|
POLLIN
|
如果设备无阻塞的读,就返回该值
|
POLLRDNORM | 通常的数据已经准备好,可以读了,就返回该值。通常的做法是会返回(POLLLIN|POLLRDNORA) |
POLLRDBAND | 如果可以从设备读出带外数据,就返回该值,它只可在linux内核的某些网络代码中使用,通常不用在设备驱动程序中 |
POLLPRI | 如果可以无阻塞的读取高优先级(带外)数据,就返回该值,返回该值会导致select报告文件发生异常,以为select八带外数据当作异常处理 |
POLLHUP | 当读设备的进程到达文件尾时,驱动程序必须返回该值,依照select的功能描述,调用select的进程被告知进程时可读的。 |
POLLERR | 如果设备发生错误,就返回该值。 |
POLLOUT | 如果设备可以无阻塞地些,就返回该值 |
POLLWRNORM | 设备已经准备好,可以写了,就返回该值。通常地做法是(POLLOUT|POLLNORM) |
POLLWRBAND | 于POLLRDBAND类似 |
static unsigned int scull_p_poll(struct file *filp, poll_table *wait) { struct scull_pipe *dev = filp->private_data; unsigned int mask = 0; /* * The buffer is circular; it is considered full * if "wp" is right behind "rp" and empty if the * two are equal. */ down(&dev->sem); poll_wait(filp, &dev->inq, wait); poll_wait(filp, &dev->outq, wait); if (dev->rp != dev->wp) mask |= POLLIN | POLLRDNORM; /* readable */ if (spacefree(dev)) mask |= POLLOUT | POLLWRNORM; /* writable */ up(&dev->sem); return mask; }
int (*fsync) (struct file *file, struct dentry *dentry, int datasync);
struct poll_table_struct;
/*
* structures and helpers for f_op->poll implementations
*/
typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);
typedef struct poll_table_struct {
poll_queue_proc qproc;
} poll_table;
struct poll_table_entry {
struct file * filp;
wait_queue_t wait;
wait_queue_head_t * wait_address;
};
struct poll_wqueues {
poll_table pt;
struct poll_table_page * table;
int error;
int inline_index;
struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES];
};
struct poll_table_page {
struct poll_table_page * next;
struct poll_table_entry * entry;
struct poll_table_entry entries[0];
};
struct fasync_struct {
int magic;
int fa_fd;
struct fasync_struct *fa_next; /* singly linked list */
struct file *fa_file;
};
int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
void kill_fasync(struct fasync_struct **fa, int sig, int band);
static int scull_p_fasync(int fd, struct file *filp, int mode) { struct scull_pipe *dev = filp->private_data; return fasync_helper(fd, filp, mode, &dev->async_queue); }
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* 注意, 一些设备也针对设备可写而实现了异步通知,在这个情况,kill_fasnyc 必须以 POLL_OUT 模式调用.*/
/* remove this filp from the asynchronously notified filp's */
scull_p_fasync(-1, filp, 0);
[Tekkaman2440@SBC2440V4]#cd /lib/modules/ [Tekkaman2440@SBC2440V4]#insmod pipe.ko [Tekkaman2440@SBC2440V4]#cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 /dev/vc/0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 7 vcs 10 misc 13 input 14 sound 81 video4linux 89 i2c 90 mtd 116 alsa 128 ptm 136 pts 180 usb 189 usb_device 204 s3c2410_serial 252 pipe 253 usb_endpoint 254 rtc Block devices: 1 ramdisk 256 rfd 7 loop 31 mtdblock 93 nftl 96 inftl 179 mmc [Tekkaman2440@SBC2440V4]#cd /dev/ [Tekkaman2440@SBC2440V4]# [Tekkaman2440@SBC2440V4]#cd /tmp/ [Tekkaman2440@SBC2440V4]#./pipe_test & [Tekkaman2440@SBC2440V4]#open scullpipe0 ! open scullpipe1 ! SCULL_P_IOCTSIZE : scull_p_buffer0=21 ! SCULL_P_IOCTSIZE : scull_p_buffer1=21 ! close pipetest0 ! close pipetest1 ! reopen scullpipe0 ! reopen scullpipe1 ! [Tekkaman2440@SBC2440V4]#echo 12345678901234567890 > /dev/scullpipe0 [Tekkaman2440@SBC2440V4]#read from pipetest0 code=20 [0]=1 [1]=2 [2]=3 [3]=4 [4]=5 [5]=6 [6]=7 [7]=8 [8]=9 [9]=0 [10]=1 [11]=2 [12]=3 [13]=4 [14]=5 [15]=6 [16]=7 [17]=8 [18]=9 [19]=0 read from pipetest0 code=1 [0]= [1]=2 [2]=3 [3]=4 [4]=5 [5]=6 [6]=7 [7]=8 [8]=9 [9]=0 [10]=1 [11]=2 [12]=3 [13]=4 [14]=5 [15]=6 [16]=7 [17]=8 [18]=9 [19]=0 [Tekkaman2440@SBC2440V4]#echo 12345678901234 > /dev/scullpipe1 [Tekkaman2440@SBC2440V4]#read from pipetest1 code=15 [0]=1 [1]=2 [2]=3 [3]=4 [4]=5 [5]=6 [6]=7 [7]=8 [8]=9 [9]=0 [10]=1 [11]=2 [12]=3 [13]=4 [14]= [15]=6 [16]=7 [17]=8 [18]=9 [19]=0 [Tekkaman2440@SBC2440V4]#ps PID Uid VSZ Stat Command 1 root 1744 S init 2 root SW< [kthreadd] 3 root SWN [ksoftirqd/0] 4 root SW< [watchdog/0] 5 root SW< [events/0] 6 root SW< [khelper] 59 root SW< [kblockd/0] 60 root SW< [ksuspend_usbd] 63 root SW< [khubd] 65 root SW< [kseriod] 77 root SW [pdflush] 78 root SW [pdflush] 79 root SW< [kswapd0] 80 root SW< [aio/0] 707 root SW< [mtdblockd] 708 root SW< [nftld] 709 root SW< [inftld] 710 root SW< [rfdd] 742 root SW< [kpsmoused] 751 root SW< [kmmcd] 769 root SW< [rpciod/0] 778 root 1752 S -sh 779 root 1744 S init 781 root 1744 S init 783 root 1744 S init 785 root 1744 S init 796 root 1344 S ./pipe_test 797 root 1744 R ps [Tekkaman2440@SBC2440V4]#./asynctest & [Tekkaman2440@SBC2440V4]#echo 12345678901234 > /dev/scullpipe0 [Tekkaman2440@SBC2440V4]#12345678901234 close pipetest0 ! exit ! [2] + Done ./asynctest [Tekkaman2440@SBC2440V4]#cat /proc/scullpipe Default buffersize is 21 Device 0: c3e18494 Queues: c04f1c34 c04f1c34 Buffer: c3dc6c08 to c3dc6c1d (21 bytes) rp c3dc6c17 wp c3dc6c17 readers 1 writers 0 Device 1: c3e18528 Queues: c04f1c6c c04f1c6c Buffer: c3dc6b38 to c3dc6b4d (21 bytes) rp c3dc6b47 wp c3dc6b47 readers 1 writers 0 Device 2: c3e185bc Queues: c3e185bc c3e185bc Buffer: 00000000 to 00000000 (0 bytes) rp 00000000 wp 00000000 readers 0 writers 0 Device 3: c3e18650 Queues: c3e18650 c3e18650 Buffer: 00000000 to 00000000 (0 bytes) rp 00000000 wp 00000000 readers 0 writers 0