Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

NOP

Возможно, вам интересно, что делает вызов nop() в цикле wait() в src/bin/spin-wait.rs.

Ответ: он буквально ничего не делает. Функция nop() заставляет компилятор поместить в это место программы машинную инструкцию Arm NOP. NOP — особая инструкция, из-за которой процессор её пропускает. Игнорирует. Буквально выполняет No OPeration, «операцию-ничего» (отсюда и название).

Итак, уберите эту строку, пересоберите программу — не забудьте режим --release — и запустите её.

Светодиод снова горит ровным светом, только немного тусклее. Без тела цикла оптимизатор компилятора решил, что функция wait() ничего не делает, и просто убрал её на этапе сборки. Спасибо, оптимизатор. Ты сделал мой цикл ожидания бесконечно быстрым.

Как же nop() выполняет свою работу? Если заглянуть в реализацию nop() (после некоторых поисков), окажется, что она устроена так:

#![allow(unused)]
fn main() {
asm!("nop", options(nomem, nostack, preserves_flags));
}

Функция nop() «встраивается» (inlined), поэтому при вызове в код программы в этом месте вставляется настоящая ассемблерная инструкция Arm NOP. Поскольку это ассемблерная вставка, компилятор не удалит и не переместит эту инструкцию: она останется там, где вы её поставили.

Возможность вставлять ассемблерный код в программу там, где это нужно, во встраиваемом программировании иногда очень важна. Бывает, что у процессора есть инструкции, о которых компилятор не знает, но без которых нельзя эффективно использовать процессор. Директива asm!() в Rust даёт возможность это сделать.

Наш цикл ожидания по-прежнему никуда не годится. Поговорим о том, как сделать лучше.