Реальные варианты использования барьеров (DSB, DMB, ISB) в ARM - программирование
Подтвердить что ты не робот

Реальные варианты использования барьеров (DSB, DMB, ISB) в ARM

Я понимаю, что DSB, DMB и ISB являются препятствиями для предотвращения переупорядочения инструкций. Я также могу найти много очень хороших объяснений для каждого из них, но довольно сложно представить, что я должен их использовать.

Кроме того, из открытых исходных кодов я вижу эти барьеры время от времени, но довольно сложно понять, почему они используются. Для примера, в ядре Linux 3.7 tcp_rcv_synsent_state_process, существует строка:

    if (unlikely(po->origdev))
            sll->sll_ifindex = orig_dev->ifindex;
    else
            sll->sll_ifindex = dev->ifindex;

    smp_mb();

    if (po->tp_version <= TPACKET_V2)
            __packet_set_status(po, h.raw, status);

где smp_mb() - это в основном DMB. Не могли бы вы дать мне некоторые из ваших реальных примеров? Это поможет лучше понять барьеры.

4b9b3361

Ответ 1

Извините, не собираюсь давать вам простой пример, как вы спрашиваете, потому что, поскольку вы уже просматриваете исходный код Linux, у вас есть много тех, кому нужно идти, и они, похоже, не помогают, Нет никакого стыда в этом - каждый здравомыслящий человек, по крайней мере, сначала путается по вопросам упорядочения доступа к памяти:)

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

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

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

Пол МакКенни написал превосходную статью о необходимости барьеров памяти и о том, какие эффекты они имеют в процессоре: Барьеры памяти: аппаратное обеспечение для программных хакеров

Если это слишком хардкорно, я написал серию блога из 3 частей, немного более легкую и заканчивающуюся видом ARM. Первая часть Порядок доступа к памяти - введение.

Но если это конкретные списки примеров, которые вам нужны, особенно для архитектуры ARM, вы можете сделать намного хуже, чем Тесты и кулинарные книги по барьеру.

Внешний вид программиста с дополнительным светом и не полностью архитектурно-правильная версия:

  • DMB - всякий раз, когда доступ к памяти требует упорядочения в отношении доступа к другой памяти.
  • DSB - всякий раз, когда доступ к памяти должен быть завершен до выполнения программы.
  • ISB - всякий раз, когда выборки команд должны явно выполняться после определенной точки в программе, например, после обновления карты памяти или после написания кода, который должен быть выполнен. (На практике это означает "выбросить любые предварительно запрограммированные инструкции на этом этапе".)

Ответ 2

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

Он очень часто использовался в DMA-передачах. Простые структуры управления DMA могут выглядеть так:

struct dma_control {
  u32 owner;
  void * data;
  u32 len;
};

У владельца обычно будет указано что-то вроде OWNER_CPU или OWNER_HARDWARE, чтобы указать, кому из двух участников разрешено работать со структурой.

Код, который изменит это, обычно будет похож на этот

dma->data = data;
dma->len  = length;
smp_mb();
dma->owner = OWNER_HARDWARE;

Итак, данные len всегда устанавливаются до того, как право собственности передается на оборудование DMA. В противном случае двигатель может получить устаревшие данные, такие как указатель или длина, которая не была обновлена, поскольку процессор переупорядочил доступ к памяти.

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

Ответ 3

Одним простым примером барьерного требования является спин-блокировка. Если вы реализуете спин-блокировку с использованием сравнения и замены (или LDREX/STREX на ARM) и без барьера, процессору разрешается спекулятивно загружать значения из памяти и лениво хранить рассчитанные значения в памяти, и ни один из них не требуется в порядке загрузки/хранения в потоке команд.

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

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