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

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

кроме того, из открытых исходных кодов я время от времени вижу эти барьеры, но довольно трудно понять, почему они используются. Например, в функции Linux kernel 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. Не могли бы вы привести несколько примеров из вашей реальной жизни? Это поможет лучше понять барьеры.

3 ответов


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

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

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

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

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

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

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

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

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

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

Он используется очень часто в 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. В противном случае двигатель может получить устаревшие данные, такие как указатель или длина, которая не была обновлена, потому что ЦП переупорядочил доступ к памяти.

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


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

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

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