Может ли процесс как-то продолжаться без сбоев после получения SIGSEGV или SIGBUS? - PullRequest
3 голосов
/ 21 мая 2019

Я работаю над проектом, который имеет дело с несколькими процессами и потоками, влияющими на одни и те же данные.У меня есть строка кода, которая может привести к ошибке сегментации, потому что данные могут быть обновлены из любой точки мира.Для этой конкретной строки, если это вызывает ошибку сегментации, я как-то хочу обработать ее, вместо того, чтобы позволить программе аварийно завершить работу.Как я могу просто обновить ячейку памяти, если предыдущая вызывала ошибку сегментации.Есть ли какой-нибудь возможный способ сделать это?

ОБНОВЛЕНИЕ (краткая сводка моего случая):

Я хочу очень быстрый доступ к файлу.Для этой цели я вызываю mmap (2) для сопоставления этого файла со всеми процессами, обращающимися к нему.Данные, которые я записываю в файл, имеют вид определенной структуры данных и занимают много памяти.Так что, если приходит момент, что отображенного мною размера недостаточно, мне нужно увеличить размер файла и снова mmap (2) этот файл с новым размером.Для увеличения размера я вызываю ftruncate (2).ftruncate (2) может вызываться из любого процесса, поэтому вместо этого он может сжать файл.Поэтому мне нужно проверить, не приводит ли память, к которой я обращаюсь, к сбоям сегмента.Я работаю на macOS.

Ответы [ 2 ]

2 голосов
/ 21 мая 2019

Это можно заставить работать, но, добавив обработчики сигналов в изображение, вы значительно усложните свои проблемы межпроцессного и межпотокового блокирования.Я хотел бы предложить альтернативный подход: зарезервировать поле на первой странице файла mmapped, чтобы указать ожидаемый размер структуры данных.Используйте fcntl блокировки файлов для обеспечения доступа к этому полю.

Когда любой процесс хочет обновить размер, он берет блокировку записи, читает текущее значение, увеличивает его, msync s страницы (достаточно использовать MS_ASYNC|MS_INVALIDATE), , затем использует ftruncate для увеличения файла, затем увеличивает его отображение файла и только после этого освобождает записьзамок.Если после взятия блокировки записи вы обнаружите, что файл уже больше требуемого размера, просто увеличьте сопоставление и снимите блокировку, не вызывайте ftruncate или не меняйте поле.

Это обеспечивает взаимодействиепроцессы никогда не уменьшат размер файла, а область памяти, отображаемая каждым процессом, всегда поддерживается выделенным хранилищем, поэтому вы никогда не должны получать SIGBUS es.Обратите внимание, что размер файла на диске будет увеличиваться только при реальной записи в только что выделенное пространство благодаря магии разреженных файлов .

1 голос
/ 21 мая 2019

Да, вы можете сделать это с помощью обработчика сигнала, который ловит SIGSEGV или SIGBUS, настраивает mmap и возвращает. Когда обработчик сигнала возвращается, он возобновляет работу с того места, где произошел сигнал, что означает, что для синхронного сигнала, такого как SIGSEGV или SIGBUS, он перезапустит ошибочную инструкцию.

Вы можете увидеть это на работе в моей реализации совместно используемой памяти malloc - найдите shm_segv в malloc.c, чтобы увидеть обработчик сигнала; это довольно просто Я никогда не пробовал этот код на MacOS, но я думаю, что он будет работать на OSX, так как он работает на всех других UNIX-системах на основе BSD, на которых я его пробовал. Существует проблема, заключающаяся в том, что, согласно спецификации POSIX, mmap не является асинхронно безопасным, поэтому его нельзя вызывать из обработчика сигнала, но во всех системах, которые фактически поддерживают отображение реальной памяти (а не эмулируют его с помощью malloc + read), это должно быть хорошо.

...