copy-on-write article on wikipedia говорит, что копирование при записи обычно осуществляется путем предоставления доступа только к страницам, так что, когда он написан, обработчик ловушки сбоя страницы может отображать для него уникальную страницу физической памяти. Поэтому мой вопрос в том, почему приложение на уровне пользователя не получает сигнал SIGSEGV, когда происходит такое нарушение страницы? В конце концов, wikipedia article on SIGSEGV говорит, что SIGSEGV - это сигнал, отправленный процессу, когда он вызывает неверную ссылку на память или ошибку сегментации. Таким образом, в этом случае, на примере копирования на запись, почему SIGSEGV не отправляется в процесс.Почему нет сигнала SIGSEGV на копирование при записи?
1
A
ответ
1
Основная идея COW заключается в том, что COW полностью прозрачна для пользовательского процесса, как будто она полностью владеет памятью без совместного использования.
2
Я знаю, что прошло какое-то время, так как это было задано, но я хотел немного рассказать об ответе Алексея.
копирования при записи (я предполагаю, что вы говорите о виртуальной памяти и не файловых систем), как правило, работает следующим образом:
- ОС знает, какие должны быть скопированы на записи страницы. (Это страницы, которые являются частями процесса.) Эти страницы отмечены как на аппаратном уровне как только для чтения. Тем не менее, карта виртуальной памяти процесса имеет страницы, помеченные как доступные для чтения и записи. Это означает, что пользовательский процесс считает, что он имеет полный доступ к рассматриваемым страницам.
- Когда пользовательский процесс пытается выполнить запись на одну из этих страниц, возникает ошибка страницы, потому что процессор распознает, что страница доступна только для чтения (на основе предшествующих аппаратных знаков). Ошибки страниц подобны segfaults, но для ядра вместо пользовательских процессов.
- Это приводит к тому, что обработчик ошибок страницы запускается в ядре, которое просматривает данную страницу и видит, что это закрытая страница, которая еще не скопирована. Обработчик создаст копию страницы и отметит копию как доступную для записи.
- Затем обработчик заменит адрес старой страницы на новый в таблице преобразования виртуального на физический и выйдет.
- Последняя инструкция будет повторно выполнена пользовательским процессом в этот момент, и на этот раз запись будет успешной, потому что новая страница будет записываться как на карту виртуальной памяти (вид пользовательских процессов на разрешения на память), так и на аппаратное обеспечение (ядро представления разрешений памяти).
Ошибка страницы возникает каждый раз, когда возникает ошибка сегментации, но большинство ошибок страницы обрабатываются ядром и никогда не передаются процессу, вызвавшему их как segfaults. Существует много причин, по которым ошибка страницы может быть обработана на более низком уровне, в том числе:
- Страница, к которой был получен доступ, выгружалась на диск, потому что она не использовалась в течение длительного времени. ОС должна вернуть его в память, чтобы процесс мог снова использовать его.
- Процесс получает доступ к недавно выделенной странице в первый раз, и фактическая физическая страница еще не выделена. ОС должна выделять страницу, а затем вставлять ее в таблицу преобразования виртуальных в физическое, прежде чем можно будет фактически использовать память.
- ОС выполняет доступ к разрешениям доступа к странице аппаратного обеспечения, чтобы он мог следить за доступом к определенной странице. Это то, что происходит при копировании на запись, но оно может иметь и другие виды использования. Рассмотрим технологию виртуализации на уровне ОС, такую как
kvm
, где запись в местоположение устройства с памятью в памяти в гостевой ОС должна фактически записываться в файл или на дисплей в ОС хоста.
Но что происходит, когда процесс воспроизводится на вилке? Я имею в виду, что после вилки, если исходный процесс изменяет какую-то страницу, ему назначается новая физическая страница, но если разветвленный процесс впоследствии изменяет одну и ту же страницу, она не выделяет какую-то новую страницу, потому что исходный процесс теперь уже имеет другую. Как это достигается? – pythonic
ОС заботится обо всех ошибках обработки этой страницы, распределении памяти и сопоставлении и копировании данных. –
user1018562, после памяти родителя fork имеет значение COWed - помечено как только для чтения, потому что теперь есть другой процесс, который ссылается на одну и ту же память. Если кто-то из них пишет, он получит pagefault, а страница будет разделена (deCOWed). Ядро будет выделять новую страницу, делать копии старых данных и перезапускать неудачную запись. Он прозрачен для пользователя, кроме увеличенного счетчика второстепенных страниц (проверьте с/usr/bin/time). PS: fork + exec - особый случай. – osgx