【发布时间】:2012-10-05 07:18:58
【问题描述】:
我正在对可以卸载的文件执行 mmap()(该文件位于用户可以随时删除的 USB 设备上),如果文件被卸载,我的应用程序将崩溃,然后我尝试访问缓冲区中的任何元素。
有什么解决办法吗?
【问题讨论】:
我正在对可以卸载的文件执行 mmap()(该文件位于用户可以随时删除的 USB 设备上),如果文件被卸载,我的应用程序将崩溃,然后我尝试访问缓冲区中的任何元素。
有什么解决办法吗?
【问题讨论】:
首先,我想说这应该作为一个很好的论据不要使用 mmap 不必要地作为“优化读取”或类似的。除了设备删除之外,其他进程截断文件等问题也可能导致访问出现SIGBUS 错误。
如果您确实需要使用mmap,您可以为SIGBUS 安装信号处理程序。它的任务基本上应该是:
SIGBUS 的全局(或线程本地,如果您的程序是多线程的)标志,以便可以知道错误代码。MAP_FIXED 调用mmap 以在错误页面的顶部映射一个新的匿名页面。可以选择用访问地图的代码将其识别为错误的数据填充它;这可能使第 1 步变得不必要。另一种方法是在访问地图之前设置一个全局(或线程本地)jmp_buf,并让信号处理程序简单地调用longjmp。
请注意,mmap 和 longjmp 都不是异步信号安全的,但有问题的 SIGBUS 不是异步信号(尽管如果错误访问发生在非异步内部,它可能应该被视为异步信号) -信号安全库函数,例如sscanf)。只要它是您自己的代码,而不是库函数,访问地图,您应该是安全的。而mmap 在大多数/所有现实世界的实现中都是异步信号安全的,因此即使第一个解决方案在实践中不正确,您也应该可以接受。
【讨论】:
mmap 的功能远比表面上看到的要多——因为错误处理比传统 I/O 复杂得多。这不一定是_反对使用_mmap 的原因……只要注意你召唤的灵魂;-)
最简单的事情是设置一个信号处理程序,它将检查对与mmaped 地址相对应的内存位置的访问。
您将使用sigaction 形式的信号处理程序,而不是更简单的signal 处理程序,因为sigaction 处理程序在与信号地址对应的struct __siginfo * 参数中接收信息。可以检查它是否在mmaped文件的地址范围内。
mmap 非常适合当您不想处理缓冲区读取/写入数据的复杂性时,但由于出现问题您只会得到一种形式的错误(信号)。使用read/write 机制,您可以获得errno 并确定发生了什么。在这种情况下,这在很大程度上是开发人员的选择。
要在收到信号后跳转到某个位置,则需要使用setjmp 和longjmp/siglongjmp - 请参阅this question 中的一些用法
【讨论】:
不要访问不可用的文件。检查文件是否还在,或者使用无法卸载的文件。
【讨论】:
SIGBUS 是否有帮助?或者类似的东西?
SIGBUS 不一定是可恢复的,尽管一些实现在从处理程序返回后重试错误指令。
setjmp()/longjmp() 能够避免错误指令的重新执行。
longjmp out(可能会很乱),或者(更容易)mmap 和MAP_FIXED 在错误页面顶部添加一个新的匿名地图。
您可以使用http://linux.die.net/man/7/inotify 获得有关文件、目录的任何更改的通知。 您可以考虑使用 IN_DELETE。
【讨论】:
read() 以了解是否有任何更改,但更改可能发生在read() 不返回任何感兴趣的内容和以下内存访问之间。这是一个竞赛条件。此外,事件队列可能会溢出。所以,这不是解决方案。