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

StackOverflow https://stackoverflow.com/questions/2484959

Вопрос

Я пишу программу, которая по соображениям производительности использует общую память (были оценены сокеты и каналы в качестве альтернатив, и они недостаточно быстры для моей задачи, вообще говоря, любой метод IPC, который включает копии, слишком медленный).В области общей памяти я пишу множество структур фиксированного размера.Существует одна программа, ответственная за запись структур в общую память, и множество клиентов, которые читают из нее.Однако в каждой структуре есть один элемент, в который клиентам необходимо записать (счетчик ссылок, который они будут обновлять атомарно).Все остальные элементы должны быть доступны для чтения только клиентам.

Поскольку клиентам необходимо изменить этот единственный элемент, они не могут отобразить область общей памяти как доступную только для чтения.Но они также не должны вмешиваться в работу других участников, и поскольку эти программы написаны на C ++, возможно повреждение памяти.В идеале одному клиенту должно быть как можно сложнее вывести из строя другой.Меня беспокоят только глючные клиенты, а не вредоносные, поэтому допускаются несовершенные решения.

Я могу попытаться остановить перезапись клиентов, объявив элементы в используемом ими заголовке как const , но это не предотвратит перезапись из-за повреждения памяти (переполнения буфера, неправильного приведения и т.д.).Я могу вставить канарейки, но тогда мне приходится постоянно оплачивать расходы на их проверку.

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

Есть ли какой-нибудь способ пометить меньшие области памяти таким образом, чтобы их запись привела к сбою вашего приложения?На некоторых платформах есть аппаратные контрольные точки, и, возможно, я мог бы активировать одну из них с помощью встроенной сборки, но на 32-разрядной x86 я был бы ограничен только 4-мя одновременно, и каждая из них могла бы охватывать только часть структуры, потому что они ограничены 4 байтами.Это также сделало бы отладку моей программы болезненной ;)

Редактировать:Я нашел эта довольно сногсшибательная статья, но, к сожалению, для этого требуется использование ECC-памяти и модифицированного ядра Linux.

Это было полезно?

Решение

Я не думаю, что возможно сделать так, чтобы несколько битов читались только таким образом на уровне операционной системы.

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

long *refCountersBase;//The start address of the ref counters page
MyStruct *structsBase;//The start address of your structures page

//get address to reference counter
long *getRefCounter(MyStruct *myStruct )
{
    size_t n = myStruct - structsBase;
    long *ref = refCountersBase + n;
    return ref;
}

Другие советы

Вам нужно было бы добавить обработчик сигнала для SIGSEGV, который восстанавливается после исключения, но только для определенных адресов.Отправной точкой может быть http://www.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html и соответствующую документацию для вашей операционной системы.

Редактировать: Я полагаю, что вы хотите выполнить запись и вернуть, если адрес записи действительно в порядке, и повторно вызвать предыдущий обработчик исключений (указатель, который вы получаете при установке вашего обработчика исключений), если вы хотите распространить исключение.Хотя у меня нет опыта в таких вещах.

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

Вы могли бы написать API, а не просто использовать заголовки.Принуждение клиентов к использованию API устранило бы большинство проблем с коррупцией.

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

Вам нужно учитывать, что у читателя может возникнуть проблема, и он не сможет должным образом обновить количество ссылок.Также то, что автору может не удастся завершить обновление.Чтобы справиться с этими вещами, требуются дополнительные проверки.Вы можете комбинировать такие проверки с API.Возможно, стоит поэкспериментировать, чтобы измерить влияние на производительность какой-либо проверки целостности.Это может быть достаточно быстро, чтобы сохранить контрольную сумму, что-то такое же простое, как adler32.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top