Spec-Zone.ru › GCC 15

7.9.2 Устаревшие встроенные функции __sync для атомарного доступа к памяти

Следующие встроенные функции предназначены для совместимости с функциями, описанными в разделе 7.4 документа «Application Binary Interface» для процессоров Intel Itanium. Поэтому они отличаются от обычной практики GCC: в их именах отсутствует префикс «__builtin_», и они перегружены, чтобы работать с несколькими типами.

В определении, приведённом в документации Intel, разрешено использовать только типы int, long, long long или их беззнаковые аналоги. GCC допускает любой скалярный тип размером 1, 2, 4 или 8 байт, кроме типа C _Bool или типа C++ bool. Операции с аргументами-указателями выполняются так, как если бы операнды имели тип uintptr_t. То есть они не масштабируются по размеру типа, на который указывает указатель.

Эти функции реализованы на основе встроенных функций «__atomic» (см. Встроенные функции атомарных операций с учётом модели памяти). Их не следует использовать в новом коде: вместо них следует использовать встроенные функции «__atomic».

Не все операции поддерживаются всеми целевыми процессорами. Если конкретную операцию невозможно реализовать на целевом процессоре, генерируется вызов внешней функции. Имя внешней функции совпадает с именем встроенной версии и дополнено суффиксом «_n», где n — размер типа данных.

В большинстве случаев эти встроенные функции считаются полным барьером. Это означает, что операнды памяти не перемещаются через операцию ни вперёд, ни назад. Кроме того, при необходимости выдаются инструкции, не позволяющие процессору спекулятивно загружать данные через операцию или ставить записи в очередь после операции.

В документации Intel для всех этих функций указано, что они принимают «необязательный список переменных, защищённых барьером памяти». Значение этого неясно: возможно, защищаются только перечисленные переменные, а возможно, это список дополнительных переменных, которые нужно защитить. GCC игнорирует этот список и считает его пустым. Пустой список GCC трактует как указание защитить все глобально доступные переменные.

Встроенная функция: type __sync_fetch_and_add (type *ptr, type value, ...)
Встроенная функция: type __sync_fetch_and_sub (type *ptr, type value, ...)
Встроенная функция: type __sync_fetch_and_or (type *ptr, type value, ...)
Встроенная функция: type __sync_fetch_and_and (type *ptr, type value, ...)
Встроенная функция: type __sync_fetch_and_xor (type *ptr, type value, ...)
Встроенная функция: type __sync_fetch_and_nand (type *ptr, type value, ...)

Эти встроенные функции выполняют операцию, указанную в имени, и возвращают значение, которое до этого находилось в памяти. То есть операции с целочисленными операндами имеют следующую семантику. Операции с аргументами-указателями выполняются так, как если бы операнды имели тип uintptr_t. То есть они не масштабируются по размеру типа, на который указывает указатель.

{ tmp = *ptr; *ptr op= value; return tmp; }
{ tmp = *ptr; *ptr = ~(tmp & value); return tmp; }   // nand

Объект, на который указывает первый аргумент, должен иметь целочисленный тип или тип указателя. Он не должен иметь логический тип.

Примечание: в GCC 4.4 и более поздних версиях __sync_fetch_and_nand реализована как *ptr = ~(tmp & value), а не как *ptr = ~tmp & value.

Встроенная функция: type __sync_add_and_fetch (type *ptr, type value, ...)
Встроенная функция: type __sync_sub_and_fetch (type *ptr, type value, ...)
Встроенная функция: type __sync_or_and_fetch (type *ptr, type value, ...)
Встроенная функция: type __sync_and_and_fetch (type *ptr, type value, ...)
Встроенная функция: type __sync_xor_and_fetch (type *ptr, type value, ...)
Встроенная функция: type __sync_nand_and_fetch (type *ptr, type value, ...)

Эти встроенные функции выполняют операцию, указанную в имени, и возвращают новое значение. То есть операции с целочисленными операндами имеют следующую семантику. Операции с операндами-указателями выполняются так, как если бы тип операнда был uintptr_t.

{ *ptr op= value; return *ptr; }
{ *ptr = ~(*ptr & value); return *ptr; }   // nand

К аргументам применяются те же ограничения, что и для соответствующих встроенных функций __sync_op_and_fetch.

Примечание: в GCC 4.4 и более поздних версиях __sync_nand_and_fetch реализована как *ptr = ~(*ptr & value), а не как *ptr = ~*ptr & value.

Встроенная функция: bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval, ...)
Встроенная функция: type __sync_val_compare_and_swap (type *ptr, type oldval, type newval, ...)

Эти встроенные функции выполняют атомарную операцию сравнения и обмена. То есть, если текущее значение *ptr равно oldval, в *ptr записывается newval.

Версия «bool» возвращает true, если сравнение успешно и записано значение newval. Версия «val» возвращает содержимое *ptr до выполнения операции.

Встроенная функция: void __sync_synchronize (...)

Эта встроенная функция устанавливает полный барьер памяти.

Встроенная функция: type __sync_lock_test_and_set (type *ptr, type value, ...)

Эта встроенная функция, согласно описанию Intel, не является традиционной операцией «проверка и установка», а представляет собой атомарную операцию обмена. Она записывает value в *ptr и возвращает предыдущее содержимое *ptr.

Многие целевые платформы поддерживают такие блокировки лишь в минимальном объёме и не поддерживают полноценную операцию обмена. В этом случае целевая платформа может предоставлять здесь урезанную функциональность, при которой единственным допустимым для записи значением является непосредственная константа 1. Фактически записываемое в *ptr значение определяется реализацией.

Эта встроенная функция не является полным барьером, а представляет собой барьер acquire. Это означает, что обращения, следующие за операцией, не могут перемещаться до неё (или выполняться спекулятивно до неё), однако предыдущие записи в память могут быть ещё не видны глобально, а предыдущие чтения из памяти могут быть ещё не завершены.

Встроенная функция: void __sync_lock_release (type *ptr, ...)

Эта встроенная функция освобождает блокировку, полученную с помощью __sync_lock_test_and_set. Обычно это означает запись константы 0 в *ptr.

Эта встроенная функция не является полным барьером, а представляет собой барьер release. Это означает, что все предыдущие записи в память видны глобально, а все предыдущие чтения из памяти завершены, однако последующие чтения из памяти не защищены от спекулятивного выполнения до барьера.

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-15.3.0/gcc/_005f_005fsync-Builtins.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API