linux 阻塞 open 作为对 EBUSY 的替代

当设备不可存取, 返回一个错误常常是最合理的方法, 但是有些情况用户可能更愿意等待 设备.

 

例如, 如果一个数据通讯通道既用于规律地预期地传送报告(使用 crontab), 也用于根据 用户的需要偶尔地使用, 对于被安排的操作最好是稍微延迟, 而不是只是因为通道当前忙 而失败.

 

这是程序员在设计一个设备驱动时必须做的一个选择之一, 并且正确的答案依赖正被解决 的实际问题.

 

对 EBUSY 的替代, 如同你可能已经想到的, 是实现阻塞 open. scullwuid 设备是一个在 打开时等待设备而不是返回 -EBUSY 的 sculluid 版本. 它不同于 sculluid 只在下面的 打开操作部分:

 

spin_lock(&scull_w_lock); while (! scull_w_available())

{

spin_unlock(&scull_w_lock);

if (filp->f_flags & O_NONBLOCK) return -EAGAIN;

if (wait_event_interruptible (scull_w_wait, scull_w_available())) return -ERESTARTSYS; /* tell the fs layer to handle it */

spin_lock(&scull_w_lock);

}

if (scull_w_count == 0)

scull_w_owner = current->uid; /* grab it */ scull_w_count++;

spin_unlock(&scull_w_lock);

 

这个实现再次基于一个等待队列. 如果设备当前不可用, 试图打开它的进程被放置到等待 队列直到拥有进程关闭设备.

 

release 方法, 接着, 负责唤醒任何挂起的进程:

 

static int scull_w_release(struct inode *inode, struct file *filp)

{

 

int temp; spin_lock(&scull_w_lock); scull_w_count--;

temp = scull_w_count; spin_unlock(&scull_w_lock);

if (temp == 0)

wake_up_interruptible_sync(&scull_w_wait); /* awake other uid's */ return 0;

}

 

这是一个例子, 这里调用 wake_up_interruptible_sync 是有意义的. 当我们做这个唤醒, 我们只是要返回到用户空间, 这对于系统是一个自然的调度点. 当我们做这个唤醒时不是 潜在地重新调度, 最好只是调用 "sync" 版本并且完成我们的工作.

 

阻塞式打开实现的问题是对于交互式用户真的不好, 他们不得不猜想哪里出错了. 交互式 用户常常调用标准命令, 例如 cp 和 tar, 并且不能增加 O_NONBLOCK 到 open 调用. 有

 

些使用磁带驱动器做备份的人可能喜欢有一个简单的"设备或者资源忙"消息, 来替代被扔 在一边猜为什么今天的硬盘驱动器这么安静, 此时 tar 应当在扫描它.

 

这类的问题(需要一个不同的, 不兼容的策略对于同一个设备)最好通过为每个存取策略实 现一个设备节点来实现. 这个做法的一个例子可在 linux 磁带驱动中找到, 它提供了多 个设备文件给同一个设备. 例如, 不同的设备文件将使驱动器使用或者不用压缩记录, 或 者自动回绕磁带当设备被关闭时.

上一篇:mysql5.7密码设置


下一篇:Ubuntu 18.04下安装SPIN教程