Почему нет сигнала SIGSEGV при копировании при записи?

В статье о копировании при записи в Википедии говорится, что копирование при записи обычно реализуется путем предоставления доступа к страницам только для чтения, так что, когда одна из них записывается, обработчик ловушки ошибки страницы может сопоставить для нее уникальную страницу физической памяти. Итак, мой вопрос: почему приложение пользовательского уровня не получает сигнал SIGSEGV, когда происходит такая ошибка страницы? В конце концов, статья Википедии о SIGSEGV говорит, что SIGSEGV — это сигнал, посылаемый процессу, когда он создает неверная ссылка на память или ошибка сегментации. Итак, в этом случае, то есть в случае копирования при записи, почему в процесс не отправляется SIGSEGV.


person pythonic    schedule 21.04.2012    source источник


Ответы (2)


Я знаю, что это было давно, но я хотел немного расширить ответ Алексея.

Копирование при записи (я предполагаю, что вы говорите о виртуальной памяти, а не о файловых системах) обычно работает так:

  1. ОС знает, какие страницы нужно копировать при записи. (Это страницы, которые являются частными для процесса.) Эти страницы отмечены аппаратно как доступные только для чтения. Однако на карте виртуальной памяти процесса страницы помечены как доступные для чтения и записи. Это означает, что пользовательский процесс считает, что он имеет полный доступ к рассматриваемым страницам.
  2. Когда пользовательский процесс пытается выполнить запись на одну из этих страниц, генерируется ошибка страницы, поскольку процессор распознает, что страница доступна только для чтения (на основе ранее установленных аппаратных меток). Ошибки страницы похожи на ошибки сегментации, но для ядра, а не для пользовательских процессов.
  3. Это запускает обработчик ошибки страницы в ядре, которое просматривает рассматриваемую страницу и видит, что это частная страница, которая еще не была скопирована. Обработчик создаст копию страницы и пометит копию как доступную для записи.
  4. Затем обработчик заменит адрес старой страницы на новый в таблице преобразования виртуального в физический и завершит работу.
  5. В этот момент пользовательский процесс повторит последнюю инструкцию, и на этот раз запись будет успешной, потому что новая страница доступна для записи как в карте виртуальной памяти (представление пользовательского процесса о разрешениях памяти), так и в аппаратном обеспечении (представление ядра о правах доступа к памяти). права доступа к памяти) уровней.

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

  • Страница, к которой был осуществлен доступ, была выгружена на диск, поскольку долгое время не использовалась. ОС должна вернуть его в память, чтобы процесс мог снова использовать его.
  • Процесс впервые обращается к недавно выделенной странице, а реальная физическая страница еще не выделена. ОС должна выделить страницу, а затем вставить ее в таблицу преобразования виртуальной памяти в физическую, прежде чем можно будет фактически использовать память.
  • ОС использует аппаратный трюк с правами доступа к странице, чтобы позволить ему отслеживать доступ к определенной странице. Это то, что происходит при копировании при записи, но оно может иметь и другое применение. Рассмотрим технологию виртуализации на уровне ОС, такую ​​как kvm, при которой запись в местоположение устройства с отображением памяти в памяти в гостевой ОС должны фактически записывать в файл или отображать в хост-ОС.
person Dan    schedule 18.06.2013

Основная идея COW заключается в том, что COW полностью прозрачен для пользовательского процесса, как если бы он полностью владел памятью без какого-либо совместного использования.

person Alexey Frunze    schedule 21.04.2012
comment
Но что происходит, когда процесс реплицирует себя на fork? Я имею в виду, что после форка, если исходный процесс изменяет какую-то страницу, ему выделяется новая физическая страница, но если разветвленный процесс впоследствии изменяет ту же страницу, он не выделяет какую-то новую страницу, потому что исходный процесс теперь уже имеет другую. Как это достигается? - person pythonic; 21.04.2012
comment
ОС заботится обо всей этой обработке ошибок страниц, распределении памяти, отображении и копировании данных. - person Alexey Frunze; 21.04.2012
comment
user1018562, после разветвления родительская память COWed - помечена как доступная только для чтения, потому что теперь есть другой процесс, который ссылается на ту же память. Если кто-то из них напишет, он получит pagefault и страница будет разделена (deCOWed). Ядро выделит новую страницу, сделает копию старых данных и перезапустит неудачную запись. Он прозрачен для пользователя, за исключением увеличенного счетчика мелких ошибок страницы (проверьте с помощью /usr/bin/time). PS: fork+exec — это особый случай. - person osgx; 19.12.2012