【问题标题】:Can a process somehow continue without crashing after receiving SIGSEGV or SIGBUS?在收到 SIGSEGV 或 SIGBUS 后,进程能否以某种方式继续而不会崩溃?
【发布时间】:2019-05-21 15:12:46
【问题描述】:

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

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

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

【问题讨论】:

  • 你可以做到:stackoverflow.com/questions/2663456/… 但那将是一个非常糟糕的设计。
  • 这种做法是错误的。您需要避免段错误。一旦你得到它,通常为时已晚。 Segfault 粗略的意思是:你的程序中某处存在错误,事情变得一团糟。
  • 我建议使用相同的数据库,例如sqlite
  • @AndrewHenle ,它在 macOS 上不可用。很抱歉在我的问题中没有提到它。我会马上更新的。
  • SysV 共享内存的另一个问题是它不支持调整共享内存对象的大小。大多数非 SysV 系统(包括 OSX,我相信)无论如何都会用映射文件模拟 SysV 共享内存。在 tmpfs(内存)文件系统上使用 mmap 几乎是最快的。

标签: c segmentation-fault signals


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2020-09-24
      • 2015-10-11
      • 1970-01-01
      • 2015-04-11
      • 2013-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-31
      相关资源
      最近更新 更多