Ответ 1
Невозможно эмулировать lock cmpxchg16b
. Это возможно, если все обращения к целевому адресу синхронизируются с отдельной блокировкой, но это включает в себя все другие инструкции, включая неатомные хранилища для любой половины объекта, и Atom-read-modify-write (например, xchg
, lock cmpxchg
, lock add
, lock xadd
) с половиной (или другой частью) 16-байтового объекта.
Вы можете эмулировать cmpxchg16b
(без lock
), как вы это делали, с исправлениями из ответа @Fifoernik. Это интересное учебное упражнение, но не очень полезно на практике, потому что реальный код, который использует cmpxchg16b
, всегда использует его с префиксом lock
.
Неатомная замена будет работать большую часть времени, потому что редкость для строки кэша недействительна из другого ядра, чтобы попасть в небольшое временное окно между двумя соседними инструкциями. Это не значит, что это безопасно, это просто означает, что он действительно трудно отлаживать, когда он иногда терпит неудачу.. Если вы просто хотите, чтобы игра работала для вашего собственного использования и может принимать случайные блокировки/ошибки, это может быть полезно. Для чего-либо, где важна правильность, вам не повезло.
Как насчет MFENCE? Кажется, это то, что мне нужно.
MFENCE
до, после или между нагрузками и хранилищами не будет препятствовать тому, чтобы другой поток видел полузаписанное значение ( "разрывание" ) или изменял данные после того, как ваш код принял решение о том, что сравнение преуспел, но прежде чем он делает магазин. Он может сократить окно уязвимости, но он не может закрыть его, потому что MFENCE
предотвращает перераспределение глобальной видимости наших собственных магазинов и загрузок. Он не может остановить магазин из другого ядра, чтобы он стал видимым для нас после наших нагрузок, но до наших магазинов. Для этого требуется цикл шины атомарного чтения-модификации-записи, для чего предназначены lock
ed инструкции.
Выполнение двух 8-байтовых атомных обменов будет решать проблему уязвимости в окне, но только для каждой половины отдельно, оставляя проблему "разрыва".
Atomic 16B load/stores решает проблему разрыва, но не проблему атомарности между нагрузками и магазинами. возможно с SSE на каком-то оборудовании, но не гарантируется, что он будет атомарным с помощью x86 ISA способом 8B естественно выровненных нагрузок и магазинов.
эмуляция Xen lock cmpxchg16b
:
В виртуальной машине Xen есть эмулятор x86, я думаю, для случая, когда виртуальная машина запускается на одном компьютере и переносится на менее работоспособное оборудование. Он эмулирует lock cmpxchg16b
, принимая глобальный замок, потому что другого пути нет. Если бы был способ подражать "правильно", я уверен, что Xen сделает это.
Как обсуждалось в этот поток списка рассылки, решение Xen по-прежнему не работает, когда эмулированная версия на одном ядре обращается к одной и той же памяти как неэмулируемая инструкция на другом ядре. (Собственная версия не учитывает глобальную блокировку).
См. также этот патч в списке рассылки Xen, который изменяет эмуляцию lock cmpxchg8b
для поддержки как lock cmpxchg8b
, так и lock cmpxchg16b
.
Я также обнаружил, что эмулятор KVM x86 не поддерживает cmpxchg16b
либо в соответствии с результатами поиска для emulate cmpxchg16b
.
Я думаю, что все это является хорошим доказательством того, что мой анализ правилен и что его невозможно безопасно эмулировать.