Я почти уверен, что на powerpc это не атомарно, но если ваша цель - одноядерная система, вы можете просто:
void update_reg_from_isr(unsigned * reg_addr, unsigned set, unsigned clear, unsigned toggle) {
unsigned reg = *reg_addr;
reg |= set;
reg &= ~clear;
reg ^= toggle;
*reg_addr = reg;
}
void update_reg(unsigned * reg_addr, unsigned set, unsigned clear, unsigned toggle) {
interrupts_block();
update_reg_from_isr(reg_addr, set, clear, toggle);
interrupts_enable();
}
Не помню, чтобы обработчики прерываний в powerpc были прерываемыми, но если они есть, то вам всегда следует использовать вторую версию.
Если ваша цель - многопроцессорная система, вы должны сделать блокировки (спин-блокировки, которые отключают прерывания на локальном процессоре, а затем подождать, пока другие процессоры завершат блокировку), которые защищают доступ к таким вещам, как аппаратные регистры, и получить необходимые блокировки перед доступом к реестру, а затем снимите блокировки сразу после того, как вы закончили обновление реестра (или регистров).
Я однажды прочитал, как реализовать блокировки в powerpc - он велел процессору следить за шиной памяти по определенному адресу, пока вы выполняли некоторые операции, а затем проверял в конце этих операций, чтобы увидеть, был ли адрес наблюдения был написан другим ядром. Если этого не произошло, то ваша операция была успешной; если это было так, вы должны были повторить операцию. Это было в документе, написанном для разработчиков компиляторов, библиотек и ОС. Я не помню, где я нашел это (вероятно, где-то на IBM.com), но небольшая охота должна показать это. Вероятно, в нем также есть информация о том, как сделать атомарный битовый поворот.