Восстанавливает ли прерванная транзакция xbegin контекст стека, существовавший при запуске xbegin?

Я заинтересован в инкапсуляции транзакционного xbegin и xend внутри функций XBEGIN() и XEND(), в статическом ассемблере lib. Однако мне неясно, как (или если) стек восстанавливается до исходного состояния вызова xbegin, учитывая xabort, происходящий на каком-то другом уровне стека (выше или ниже). Другими словами, является ли контекст динамического стека (включая эффекты прерываний) управляемым и откатывается как просто еще одна часть транзакции?

Этот подход на ассемблере необходим для сборки VC++ 2010, которая не поддерживает или не поддерживает встроенные функции _xbegin () и _xend (), а сборки x64 не могут использовать вставку _asm { }.

1 ответ

Решение

Связанные: см. также рецензию Дэвида Кантера на 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 не вызывайте слишком много абортов.

Другие вопросы по тегам