Проблемы с чтением общего буфера mmap

У меня есть модуль ядра, который выделяет большой буфер памяти, затем этот буфер перенаправляется с помощью mmap в пользовательское пространство.
Модуль получает некоторые данные от оборудования, а затем помещает новые данные в буфер с флагом перед ним. . (память инициализируется нулем, флаг равен 1).

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

упрощенная версия кода:

uint8_t * getData()
{
    while(1)
   {
      if(*((volatile uint32_t*)this->buffer) == 1)
          return this->buffer+sizeof(uint32_t);
   }
}

область памяти отображается как совместно используемая, и полный дамп памяти буфера подтверждает правильность записи в буфер.

Проблема в том, что после определенного количества правильных чтений эта функция перестает возвращаться.
Может ли это быть связано с кэшированием ЦП? Есть ли способ обойти это и убедиться, что чтение каждый раз выполняется непосредственно из ОЗУ, а не из кеша?


person Lifesworder    schedule 07.02.2012    source источник
comment
Это очень зависит от архитектуры, и вы не сказали нам свою архитектуру. В целом, создания барьера сохранения/освобождения после записи в ядре и барьера загрузки/получения перед чтением в пользовательском пространстве должно быть достаточно, если это действительно проблема.   -  person Useless    schedule 08.02.2012
comment
@Lifesworder выглядит так, как будто вы новый пользователь, но этикет здесь требует ответа, когда вы задаете вопрос, и вам предлагают несколько ответов.   -  person chetan    schedule 09.02.2012
comment
Прошу прощения, сроки, много дел :). Я не уверен, что вызвало проблему в первую очередь, но кажется, что удаление флагов MAP_SHARED и MAP_LOCKED из обработчика mmap в пространстве ядра устранило проблему...   -  person Lifesworder    schedule 11.02.2012
comment
Я имею в виду VM_LOCKED и VM_SHARED из флагов vma-›.   -  person Lifesworder    schedule 11.02.2012


Ответы (2)


Да, это, вероятно, из-за кеша процессора на стороне считывателя. Можно подумать, что ключевое слово «volatile» должно защищать от такого рода проблем, но это не совсем так, поскольку volatile — это просто директива для компилятора не регистрировать переменную, а не совсем то же самое, что указание процессору читать напрямую из основной памяти. каждый раз.

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

person chetan    schedule 08.02.2012
comment
Поскольку я тестировал одноядерный процессор, это не помогло моей проблеме как таковой, но ваш ответ пригодится, когда мне придется портировать это для работы на многоядерном процессоре (что я и сделаю). - person Lifesworder; 11.02.2012
comment
ааа... интересно. Почему-то в наши дни легко предположить, что все работают на многоядерных системах. - person chetan; 14.02.2012

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

person caf    schedule 08.02.2012