Assembler - язык неограниченных возможностей


Повторная входимость


Пусть у нас есть собственный обработчик программного прерывания, который вызывают обработчики двух аппаратных прерываний, и пусть эти аппаратные прерывания произошли сразу одно за другим. В этом случае может получиться так, что второе аппаратное прерывание осуществится в тот момент, когда еще не закончится выполнение нашего программного обработчика. В большинстве случаев это не приведет ни к каким проблемам, но, если обработчик обращается к каким-либо переменным в памяти, могут произойти редкие, невоспроизводимые сбои в его работе. Например, пусть в обработчике есть некоторая переменная counter, используемая как счетчик, считающий от 0 до 99:

mov al,byte ptr counter ; считать счетчик в AL, cmp al,100 ; проверить его на переполнение, jb counter_ok ; если счетчик достиг 100, ; >>> здесь произошло второе прерывание <<< sub al,100 ; вычесть 100 mov byte ptr counter,al ; и сохранить счетчик counter_ok:

Если значение счетчика было, например, 102, а второе прерывание произошло после проверки, но до вычитания 100, второй вызов обработчика получит то же значение 102 и уменьшит его на 100. Затем управление вернется, и следующая команда sub al,100 еще раз уменьшит AL на 100 и запишет полученное число на место. Если затем по значению счетчика вычисляется что-нибудь вроде адреса в памяти для записи, вполне возможно, что произойдет ошибка. О таком обработчике прерывания говорят, что он не является повторно входимым.

Чтобы защитить подобные критические участки кода, следует временно запретить прерывания, например так:

cli ; запретить прерывания mov al,byte ptr counter cmp al,100 jb counter_ok sub al,100 mov byte ptr counter,al counter_ok: sti ; разрешить прерывания

Следует помнить, что, пока прерывания запрещены, система не отслеживает изменения часов, не получает данных с клавиатуры, так что прерывания надо обязательно, при первой возможности, разрешать. Всегда лучше пересмотреть используемый алгоритм и, например, хранить локальные переменные в стеке или использовать специально разработанную команду CMPXCHG, которая позволяет одновременно провести сравнение и запись в глобальную переменную.




Начало  Назад  Вперед