Linux 设备驱动程序 3Ed 文件 IO 以及如何使用解释性 UML 图影响调度
Linux Device Drivers 3Ed File IO & How to Influence Scheduling with Explanatory UML Diagrams
我使用 UMLet 绘制了一些 UML 图,描述了 Linux Device Drivers 3Ed (LDD3) 的每一章的各种实体关系,作者是 Corbet、Rubini、Kroah-Hartman。最新版本的图表可以在这里找到:
Linux Device Drivers 3Ed UML Diagrams
我想请求帮助理解上面链接的非阻塞文件 IO 序列图中的文档支持的调度问题,以及 P156-158 上的 LDD3,特别是这段代码scull_getwritespace() 的片段(另见 P156,但此代码已更新为使用互斥量而不是信号量):
/* Wait for space for writing; caller must hold device semaphore. On
* error the semaphore will be released before returning. */
static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
{
while (spacefree(dev) == 0) { /* full */
DEFINE_WAIT(wait);
mutex_unlock(&dev->mutex);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
PDEBUG("\"%s\" writing: going to sleep\n",current->comm);
prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
if (spacefree(dev) == 0)
schedule();
finish_wait(&dev->outq, &wait);
if (signal_pending(current))
return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
if (mutex_lock_interruptible(&dev->mutex))
return -ERESTARTSYS;
}
return 0;
}
特别是:
if(spacefree(dev) == 0)
schedule();
感兴趣的案例是这样的:
- spacefree(dev) == 0 为真,写入进程即将调用schedule()。
- 在调用 schedule() 之前,读取进程发出 wake_up_interruptible(&dev->outq) 已经消耗了所有缓冲区数据,因此应该唤醒写入进程,以便它可以产生更多数据。这会将写入进程状态设置回 TASK_RUNNING.
- 写入进程调用 schedule() 并可能进入睡眠状态。
以上是为了避免竞争条件。
这是我的问题:
- 是否可以修改内核的 code/operation 以便我可以保证 schedule() 不会进入休眠状态而是 returns 立即从调用开始?我对 schedule() 的理解不够详细,无法回答这个问题,我们将不胜感激。我认为答案是否定的,因为调度程序可以选择接下来发生的事情,并且可能有软件中断、微线程或信号要处理。
- 是否可以修改代码,保证在重新进入读进程之前写进程运行?同样,我认为答案可能是否定的,但也许线程优先级有一些可能性。
我发现 linux 内核实体的图形表示对于理解内核中的模式非常有帮助,这大大提高了我的编码效率,但是手工生成它们非常乏味。为了节省时间,有没有其他人针对 LDD3 做过类似的事情?
谢谢。
不确定您是否有机会进入内核映射http://www.makelinux.net/kernel_map/
我使用 UMLet 绘制了一些 UML 图,描述了 Linux Device Drivers 3Ed (LDD3) 的每一章的各种实体关系,作者是 Corbet、Rubini、Kroah-Hartman。最新版本的图表可以在这里找到:
Linux Device Drivers 3Ed UML Diagrams
我想请求帮助理解上面链接的非阻塞文件 IO 序列图中的文档支持的调度问题,以及 P156-158 上的 LDD3,特别是这段代码scull_getwritespace() 的片段(另见 P156,但此代码已更新为使用互斥量而不是信号量):
/* Wait for space for writing; caller must hold device semaphore. On
* error the semaphore will be released before returning. */
static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
{
while (spacefree(dev) == 0) { /* full */
DEFINE_WAIT(wait);
mutex_unlock(&dev->mutex);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
PDEBUG("\"%s\" writing: going to sleep\n",current->comm);
prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
if (spacefree(dev) == 0)
schedule();
finish_wait(&dev->outq, &wait);
if (signal_pending(current))
return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
if (mutex_lock_interruptible(&dev->mutex))
return -ERESTARTSYS;
}
return 0;
}
特别是:
if(spacefree(dev) == 0)
schedule();
感兴趣的案例是这样的:
- spacefree(dev) == 0 为真,写入进程即将调用schedule()。
- 在调用 schedule() 之前,读取进程发出 wake_up_interruptible(&dev->outq) 已经消耗了所有缓冲区数据,因此应该唤醒写入进程,以便它可以产生更多数据。这会将写入进程状态设置回 TASK_RUNNING.
- 写入进程调用 schedule() 并可能进入睡眠状态。
以上是为了避免竞争条件。
这是我的问题:
- 是否可以修改内核的 code/operation 以便我可以保证 schedule() 不会进入休眠状态而是 returns 立即从调用开始?我对 schedule() 的理解不够详细,无法回答这个问题,我们将不胜感激。我认为答案是否定的,因为调度程序可以选择接下来发生的事情,并且可能有软件中断、微线程或信号要处理。
- 是否可以修改代码,保证在重新进入读进程之前写进程运行?同样,我认为答案可能是否定的,但也许线程优先级有一些可能性。
我发现 linux 内核实体的图形表示对于理解内核中的模式非常有帮助,这大大提高了我的编码效率,但是手工生成它们非常乏味。为了节省时间,有没有其他人针对 LDD3 做过类似的事情?
谢谢。
不确定您是否有机会进入内核映射http://www.makelinux.net/kernel_map/