Я заинтересован в инкапсуляции транзакционного xbegin и xend внутри функций XBEGIN () и XEND (), в статическом ассемблере lib. Однако мне неясно, как (или если) стек восстанавливается до исходного состояния вызова xbegin, учитывая xabort, происходящий на каком-то другом уровне стека (выше или ниже). Другими словами, является ли контекст динамического стека (включая эффекты прерываний) управляемым и откатывается как просто еще одна часть транзакции?
Этот подход на ассемблере необходим для сборки VC ++ 2010, которая не поддерживает или не поддерживает встроенные функции _xbegin () и _xend (), а сборки x64 не могут использовать вставку _asm {}.
связанные: см. также Описание TSX Дэвида Кантера для некоторой теории о том, как это работает под капотом и как программное обеспечение может извлечь из этого выгоду, и этот блог для некоторых экспериментальных показателей производительности на HSW (до обнаружения ошибки TSX и обновления микрокода отключали TSX на этом оборудовании.)
Intel insn ref руководство запись для xbegin
довольно ясно. (См. x86 пометьте вики ссылками на официальный PDF-файл Intel и другие материалы.)
При прерывании RTM логический процессор сбрасывает все архитектурное
регистрация и обновления памяти выполняется во время выполнения RTM и
восстанавливает архитектурное состояние до соответствующего внешнему
Инструкция XBEGIN. Запасной адрес, следующий за прерыванием, вычисляется из самой внешней инструкции XBEGIN.
Таким образом, инструкция работает как условная ветвь, где условие ветвления «произошло прерывание раньше XEND
? «Например:
; NASM syntax, I assume MASM is similar
ALIGN 16
retry:
; eax holds abort info, all other architectural state + memory is unchanged
inc [retry_count] ; or whatever other debug instrumentation you want to add
global xbegin_wrapper_with_retry
xbegin_wrapper_with_retry:
xbegin retry
ret
Если произойдет прерывание, это как если бы весь код, который запускался после xbegin
вообще не бегал, просто перейти к резервному адресу с eax
модифицирована.
Конечно, вы можете захотеть сделать что-то иное, чем просто бесконечные повторные попытки прерывания. Это не должно быть реальным примером. (Эта статья действительно есть реальный пример логики, которую вы могли бы использовать, используя встроенные функции. Похоже они просто тестируют eax
вместо использования xbegin
как прыжок в if
, если компилятор не оптимизирует эту проверку. ИДК, если это самый эффективный способ.)
Что вы имеете в виду «прерывает эффекты»? В текущих реализациях все, что изменяет уровень привилегий (например, системный вызов или прерывание), вызывает прерывание транзакции. Таким образом, изменения уровня кольца никогда не нужно откатывать. Процессор просто прервет транзакцию, когда встретится с чем-либо, что он не может откатить. Это означает, что возможные ошибки включают в себя что-то внутри транзакции, которое всегда вызывает прерывание, но не то, что вы делаете что-то, что не может быть отменено.
Вы можете попытаться заставить компилятор выдавать трехбайтовый XEND
инструкция без вызова функции, поэтому помещение адреса возврата в стек не является частью транзакции. например
// no idea if this is safe, or if it might get reordered by the optimizer
#define xend_MSVC __asm _emit 0x0F __asm _emit 0x01 __asm _emit 0xD5
Я думаю, что это все еще работает в 64-битном режиме, поскольку документ упоминает rax
и похоже Заголовочный файл IACA использования __asm _emit
,
Будет безопаснее поставить XEND
в своей собственной функции-обертке тоже, наверное. Вам просто нужен временный интервал, пока вы не сможете перейти на компилятор со встроенными функциями, поэтому он не должен быть идеальным, пока дополнительные операции чтения / записи из ret
а также call
не вызывайте слишком много абортов.
Других решений пока нет …