支持阻塞操作的globalfifo设备驱动(三)

static ssize_t globalfifo_read(struct file *filp, char __user *buf,
2 size_t count, loff_t *ppos)
3{
4int ret;
5struct globalfifo_dev *dev = filp->private_data; // 获得设备结构体指针
6DECLARE_WAITQUEUE(wait, current); // 调用DECLARE_WAITUEUE()创建一个等待队列的项
7
8mutex_lock(&dev->mutex);
9add_wait_queue(&dev->r_wait, &wait);调用add_wait_queue()把自己加入到等待队列中,该队列会在等待的条件满足时唤醒它
10//将r_wait提前挂入等待队列,因为后面我们需要明确编码将进程置于睡眠(当无数据可读时),这与调用down()函数时由内核将当/前进程置于睡眠状态是一致的,不同的是,调用down是内核在资源不可用时将进程置于睡眠,而此时我们根据有无数据主动将进程置于睡眠状态,因为当无数可读时,而用户又没设置NOR_BLOCK标志位,我们不能继续占用CPU需要让出CPU,从而让写进程有可能向临界区写数据;
11while (dev->current_len == 0) { // 等待FIFO非空
12 if (filp->f_flags & O_NONBLOCK) {
/*
*通过filp->f_flags标志获得用户空间是否要求非阻塞访问,驱动中可以依据此标志判断用户究竟要求阻塞还是非阻塞访问,从而进行不同的处理。
*/
13 ret = -EAGAIN;
14 goto out;
15 }
16 __set_current_state(TASK_INTERRUPTIBLE);// 调用_set_current_state()将进程明确置于睡眠
17 mutex_unlock(&dev->mutex);
18
19 schedule(); // 调度其它进程,
/*
schedule()函数调度其它进程执行,注意当前进程被设置为TASK_INTERRUPTIBLE状态,即可中断睡眠,这个状态的进程被排除在进程调度资格之外,直到被唤醒(即进入TASK_RUNNING状态),这个唤醒执行由globalfifo_write函数或者由某个中断函数的进程唤醒。
*除了被globalfifo_write函数唤醒外,还有一种被唤醒的可能,即进程接受到一个外部中断,如下代码即检查这种情况,如用户等不及了,使用ctrl+C进行中断读进程操作,那么对ctrl+C的捕捉在此处完成:
*signal_pending(current):检查当前进程是否有信号处理,返回不为0:表示有信号要处理。
*-ERESTARTSYS表示信号函数处理完毕后重新执行信号函数前的某个系统调用。
*也就是说如果信号函数前有发生系统调用,在调度用户信号函数之前,内核会检查系统调用的返回值,查看是不是因为这个信号而中断
*了系统调用,如果返回值-ERESTARTSYS,并且当前调度的信号具备-ESTARTSYS属性,系统就会在用户信号函数返回之后在执行该
*系统调用。
*/
20 if (signal_pending(current)) {
21 ret = -ERESTARTSYS;
22 goto out2;
23 }
24
25 mutex_lock(&dev->mutex);
26}
27// 如果要读的字节数大于FIFO中当前字节数,将count赋值为current_len
28if (count > dev->current_len)
29 count = dev->current_len;
30
31if (copy_to_user(buf, dev->mem, count)) {
32 ret = -EFAULT;
33 goto out;
34} else {
35 memcpy(dev->mem, dev->mem + count, dev->current_len - count);
36 dev->current_len -= count;
37 printk(KERN_INFO “read %d bytes(s),current_len:%d\n”
, count,
38 dev->current_len);
39
40 wake_up_interruptible(&dev->w_wait);
41
42 ret = count;
43}
44 out:
45mutex_unlock(&dev->mutex);;
46 out2:
47remove_wait_queue(&dev->w_wait, &wait);// 在函数退出前,将当前进程从w_wait队列中删除
48set_current_state(TASK_RUNNING);
49return ret;
50}
51
52static ssize_t globalfifo_write(struct file filp, const char __user buf,
53 size_t count, loff_t *ppos)
54{
55struct globalfifo_dev *dev = filp->private_data;
56int ret;
57DECLARE_WAITQUEUE(wait, current);
58
59mutex_lock(&dev->mutex);
60add_wait_queue(&dev->w_wait, &wait);
61
62while (dev->current_len == GLOBALFIFO_SIZE) {
63 if (filp->f_flags & O_NONBLOCK) {
64 ret = -EAGAIN;
65 goto out;
66 }
67 __set_current_state(TASK_INTERRUPTIBLE);
68
69 mutex_unlock(&dev->mutex);
70
71 schedule();
72 if (signal_pending(current)) {
73 ret = -ERESTARTSYS;
74 goto out2;
75 }
76
77 mutex_lock(&dev->mutex);
78}
79
80if (count > GLOBALFIFO_SIZE - dev->current_len)
81 count = GLOBALFIFO_SIZE - dev->current_len;
82
83if (copy_from_user(dev->mem + dev->current_len, buf, count)) {
84 ret = -EFAULT;
85 goto out;
86} else {
87 dev->current_len += count;
88 printk(KERN_INFO “written %d bytes(s),current_len:%d\n”
, count,
89 dev->current_len);
90
91 wake_up_interruptible(&dev->r_wait);
92
93 ret = count;
94}
95
96 out:
97mutex_unlock(&dev->mutex);;
98 out2:
99remove_wait_queue(&dev->w_wait, &wait);
100set_current_state(TASK_RUNNING);
101return ret;
102}

猜你喜欢

转载自blog.csdn.net/aaaa255116/article/details/81661581