энергозависимый и компиляторный барьер с встроенной сборкой - PullRequest
5 голосов
/ 24 июня 2011

В нашем продукте есть встроенная мьютексная реализация, использующая различные специфичные для платформы и компилятора методы для аппаратных частей. Одно из наших «правил» для некоторого чрезмерно оптимизированного кода, который пытается «обмануть», заключается в том, что если к переменной обращаются за пределами мьютекса и внутри, то эта переменная должна быть объявлена ​​как volatile. Я полагал, что это применимо и к непрозрачным реализациям мьютекса (таким как pthread_mutex_lock / unlock), и это привело к интересной дискуссии.

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

int v = pSharedMem->myVariable ;

__asm__ __volatile__(( "isync" : : :"memory" ))

v = pSharedMem->myVariable ;

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

В этом фрагменте кода у нас есть барьер компилятора, который предотвращает перезапись кода, как если бы он был следующим

int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;

__asm__ __volatile__(( "isync" : : :"memory" ))

или

__asm__ __volatile__(( "isync" : : :"memory" ))

int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;

(то есть: оба этих переупорядочения компилятора должны быть запрещены атрибутом volatile )

У нас также есть сам isync, который предотвращает первое переупорядочение во время выполнения (но я не думаю, что предотвращает второе, что не так интересно).

Тем не менее, мой вопрос заключается в том, что если myVariable не объявлен как volatile, является ли ограничение «памяти» достаточным, чтобы gcc обязательно перезагружал «v» после isync? Я все еще был бы склонен к обязательному использованию volatile для такого шаблона, так как этот вид кода слишком чувствителен ко всем встроенным компиляторам платформы. Тем не менее, если мы сократим обсуждение только до GCC и этого фрагмента кода, достаточно ли этого ограничения памяти asm для того, чтобы код генерировался с парой загрузок вместо одной?

1 Ответ

2 голосов
/ 24 июня 2011

__asm__ __volatile__ с "memory" клоббером требуется и будет действовать как барьер полного переупорядочения. volatile в переменной не требуется. Фактически, если вы посмотрите на определение ядра Linux atomic_t , оно не использует никаких модификаторов volatile и полностью полагается на операторы __asm__ __volatile__ с соответствующими ограничениями.

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

...