在收到 SIGSEGV 或 SIGBUS 后,进程能否以某种方式继续而不会崩溃?

Can a process somehow continue without crashing after receiving SIGSEGV or SIGBUS?

我正在处理一个处理影响相同数据的多个进程和线程的项目。我有一行代码可能会导致分段错误,因为可以从任何地方更新数据。 对于该特定行,如果它导致分段错误,我想以某种方式处理它而不是让程序崩溃。 如果前一个导致分段错误,我可以简单地更新内存位置。 有什么办法可以做到吗?

更新(我的案例的简短摘要):

我想要极速访问文件。 为此,我调用 mmap(2) 将该文件映射到访问它的所有进程。我写入文件的数据采用特定数据结构的形式,它会占用大量内存。因此,如果我映射的大小不够,我需要增加文件大小并使用新大小再次 mmap(2) 该文件。为了增加大小,我调用了 ftruncate(2)。 ftruncate(2) 可能会从任何进程调用,因此它最终可能会缩小文件。所以我需要检查我正在访问的内存是否不会导致段错误。 我正在使用 macOS。

这个 可以 工作,但是通过将信号处理程序引入画面,您会使 inter-process 和 inter-thread 锁定问题变得更加复杂。我想建议一种替代方法:在映射文件的第一页中保留一个字段,以指示数据结构的预期大小。使用 fcntl 文件锁调解对此字段的访问。

当任何进程想要更新大小时,它需要一个写锁,读取当前值,增加它,msync页面(使用MS_ASYNC|MS_INVALIDATE应该足够了),then使用ftruncate放大文件,然后放大它对文件的映射,然后才释放写锁。如果在拿了写锁之后,发现文件已经比你想要的大了,就把你的映射放大,把锁放下,不要调用ftruncate,也不要改变字段。

这确保协作进程永远不会使文件变小,并且每个进程映射的内存区域始终由分配的存储支持,因此您永远不会得到任何 SIGBUSes。请注意,磁盘上文件的大小只会在您实际写入新分配的 space 时增加,这要归功于 sparse files.

的魔力

是的,您可以使用捕获 SIGSEGV 或 SIGBUS 的信号处理程序来完成这项工作,调整 mmap 和 returns。当信号处理程序 returns 它将在信号发生的地方恢复,这意味着对于像 SIGSEGV 或 SIGBUS 这样的同步信号,它将重新运行错误指令。

您可以在我的 shared memory malloc 实现中看到这一点——在 malloc.c 中搜索 shm_segv 以查看信号处理程序;这很简单。我从未在 MacOS 上尝试过这段代码,但我认为它可以在 OSX 上运行,因为它可以在我试过的所有其他 BSD-derived UNIX 上运行。有一个问题,根据 POSIX 规范,mmap 不是异步安全的,因此不能从信号处理程序调用,但在所有实际支持真实内存映射的系统上(而不是用 malloc+read 模拟它) ) 应该没问题。