Подтвердить что ты не робот

Почему volatile работает для setjmp/longjmp

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

Теперь мой вопрос - почему волатильность работает в этой ситуации? Не изменится ли эта изменчивая переменная, все еще не получившая longjmp? Например, как longjmp будет работать правильно в приведенном ниже примере? Когда код вернется к setjmp после longjmp, не будет ли значение local_var равным 2 вместо 1?

void some_function()
{
  volatile int local_var = 1;

  setjmp( buf );
  local_var = 2;
  longjmp( buf, 1 );
}
4b9b3361

Ответ 1

setjmp и longjmp. Если переменная хранится в регистре, ее значение теряется после longjmp.

И наоборот, если он объявлен как volatile, то каждый раз, когда он записывается, он возвращается в память и каждый раз, когда он считывается, он каждый раз считывает данные из памяти. Это ухудшает производительность, потому что компилятор должен делать больше доступа к памяти вместо использования регистра, но это делает использование переменной безопасным перед longjmp ing.

Ответ 2

В этом сценарии основное внимание уделяется оптимизации: оптимизатор, естественно, ожидает, что вызов функции, такой как setjmp(), не изменяет никаких локальных переменных и не оптимизирует доступ к чтению для этой переменной. Пример:

int foo;
foo = 5;
if ( setjmp(buf) != 2 ) {
   if ( foo != 5 ) { optimize_me(); longjmp(buf, 2); }
   foo = 6;
   longjmp( buf, 1 );
   return 1;
}
return 0;

Оптимизатор может оптимизировать линию optimize_me, потому что foo был записан в строке 2, не нужно читать в строке 4 и может считаться равным 5. Кроме того, назначение в строке 5 можно удалить, поскольку foo будет никогда не читайте снова, если longjmp был нормальным функтором C. Однако setjmp() и longjmp() нарушают поток кода способом, который оптимизатор не может учитывать, нарушая эту схему. Правильным результатом этого кода было бы прекращение; с оптимизированной линией, у нас бесконечный цикл.

Ответ 3

Наиболее распространенной причиной проблем в отсутствие "летучего" классификатора является то, что компиляторы часто помещают локальные переменные в регистры. Эти регистры почти наверняка будут использоваться для других вещей между setjmp и longjmp. Самый практичный способ гарантировать, что использование этих регистров для других целей не заставит переменные удерживать неправильные значения после того, как longjmp будет кэшировать значения этих регистров в jmp_buf. Это работает, но имеет побочный эффект, что компилятор не может обновить содержимое jmp_buf, чтобы отразить изменения, внесенные в переменные после кэширования регистров.

Если это единственная проблема, результат доступа к локальным переменным, не объявленным volatile, будет неопределенным, но не Undefined Поведение. Там проблема даже с переменными памяти, однако, на что thiton ссылается: даже если локальная переменная будет выделена в стеке, компилятор будет свободен, чтобы перезаписать эту переменную чем-то еще в любое время, когда она определит, что ее значение больше не необходимо. Например, компилятор может определить, что некоторые переменные никогда не "живут", когда подпрограмма вызывает другие подпрограммы, помещает эти переменные неглубоко в свой стек стека и всплывает перед вызовом других подпрограмм. В таком сценарии, несмотря на то, что переменные существовали в памяти при вызове setjmp(), эта память могла быть повторно использована для чего-то еще, такого как сохранение обратного адреса. Таким образом, после выполнения longjmp() память считается неинициализированной.

Добавление "изменчивого" квалификатора в определение переменной заставляет зарезервировать хранилище исключительно для использования этой переменной до тех пор, пока оно находится в пределах области видимости. Независимо от того, что происходит между setjmp и longjmp, если элемент управления не вышел из области, где была объявлена ​​переменная, ничто не может использовать это местоположение для каких-либо других целей.