; нается адрес флажка критической
; секции
CErrFlg DW 0,0 ; здесь при инициализации запоми-
; нается адрес флажка критической
; ошибки
DOSSafe PROC NEAR
DOSNotSafe:
stc ;;; индикация, что "небезопасно"
ret ;;; и возврат
DOSSafeCheck:
inc cs:BusyFlag ;;; попытка снять блокировку
jg DOSNotSafe ;;; если больше -- то некоторые
;;; уже имеют блокировку
pushr ;;; сохранение, т.к. мы можем по-
;;; лучить при INDosFlag
lds si,DWORD PTR cs:CSectFlg ;;; ds:si <== адрес
;;; флажка критической секции
lodsb ;;; al <== значение флажка крити-
;;; ческой секции
lds si,DWORD PTR cs:CErrFlg ;;; ds:si <== адрес
;;; флажка критической ошибки
or al,BYTE PTR [si] ;;; вычисление ненулевого
;;; флажка критической ошибки
popr
jnz DOSNotSafe ;;; если не 0, то либо критичес-
- 4-41 -
;;; кая ошибка, либо int 21
clc ;;; индикация, что "безопасно"
ret ;;; и возврат
DOSSafe ENDP
----------------------------------------------------------------
Переключение стека и сохранение регистров
Стек является важной составной частью среды программы. Так
как повторная активация происходит в результате прерывания, то
способ определения используемого стека или доступного пространс-
тва стека отсутствует. Стеки, используемые диспетчером прерывания
int 21h, достаточно большие, чтобы разместить значения всех ре-
гистров процессора. Любая прерванная программа также должна иметь
возможность использовать оставшуюся память стека, иначе она не
сможет выполнять запросы BIOS. Диспетчер BIOS сохраняет все ре-
гистры в текущем стеке.
Перед повторной активацией TSR, программа ISR должна сохра-
нить все регистры и переключиться на личный стек TSR. Разумно
сохранять регистры в том стеке, который использовался в момент
возникновения прерывания. Оба значения стека и регистров являются
частью одного и того же контекста программы, и стек должен иметь
необходимое пространство для этих значений.
Организация "ловушек" break и критических ошибок
Следующий шаг в последовательности активации связан с измене-
нием информации состояния, которую DOS записала относительно те-
кущей программы. В этой точке Ваша TSR теперь становится текущей
программой. Так как критические ошибки и критические break могут
завершить текущую программу, необходимо быть уверенным в том, что
Вы получили шанс вернуться обратно и нашли способ как это сде-
лать. Установка своих собственных драйверов критической ошибки и
break позволяет TSR быть аккуратной в таких случаях и обходиться
с ними безопасным способом.
В связи с отсутствием способа определения из программы ISR
текущей программы переднего плана, установка драйверов критичес-
кой ошибки и break является искусным приемом программирования.
Если для манипуляции входом IVT используется int 21, то существу-
ет определенный риск получения ошибки break . Самым безопасным
способом является способ манипуляции входами IVT непосредственно.
Заметим, что необходимо запретить break , пока производится изме-
нение входов таблицы. Хотя это и не кажется очевидным, другие
программы могут прервать Вашу программу в середине выполнения из-
менений, и могут модифицировать входы IVT, с которыми Вы работае-
те. Как выполнить эту задачу, показывает листинг 4-28.
Действия, которые будут выполняться во вновь установленных
драйверах break и критической ошибки, зависят от TSR. Они могут
быть проигнорированы, но, обычно, программа при возникновении
критической ошибки должна выполнить какие-либо действия. Если TSR
может иметь дело со сбойными запросами int 21h (практически, не-
обходимо проверять результаты выполнения каждого запроса и быть
готовым иметь дело с ошибками), то простейшим способом обработки
является отказ от вызова. В то же время имеются другие способы
обработки. Например, если произошел сбой диска в связи с тем, что
была открыта дверца накопителя, то необходимо напечатать сообще-
ние и повторить операцию.
- 4-42 -
Листинг 4-28. "Ловушка" критических ошибок и break из ISR
----------------------------------------------------------------
IVT SEGMENT AT 00h ; отметить абсолютный адрес
ORG 23h*4 ; мы не заботимся относительно
; 0 - 22h
IVT23 DW 0,0 ; входы ссылок для int 23h и
IVT24 DW 0,0 ; int 24h
IVT ENDS
_text SEGMENT BYTE PUBLIC 'code'
OldInt23 DW 0.0 ; здесь мы будем сохранять адре-
OldInt24 DW 0,0 ; са критической ошибки и преры-
; вания
ASSUME ds:_text
BKGNewErrHndlr PROC NEAR
pushr ; сохранение всех изменяе-
; мых регистров
cld ; вывод флажка направления в из-
; вестное состояние для movsw и
; stosw
mov ax,cs ; es указывает на сегмент, содер-
mov es,ax ; жащий OldInt23
xor ax,ax ; ds указывает
mov ds,ax ; на IVT
ASSUME ds:IVT,es:_text ; сообщить MASM, что ожидание
mov si,OFFSET IVT23 ; установить копию IVT
mov di,OFFSET OldInt23 ; входы с movsw
mov cx,4 ; каждый вход 2 слова
cli ; В А Ж Н О !!!
rep movsw ;;; копирование текущих входов
;;; ivt
mov es,ax ;;; es теперь указывает на IVT
ASSUME es:IVT ;;; сообщить MASM об изменении
mov ax,OFFSET NewInt23 ;;; ввод новых значений
stosw ;;; в IVT
mov ax,cs
stosw
mov ax,OFFSET NewInt24
stosw
mov ax,cs
stosw
sti
popr
ASSUME ds:_text
ret
BKGNewErrHndlr ENDP
NewInt23 PROC FAR ; новый обработчик break
iret ; игнорирование break
NewInt23 ENDP
NewInt24 PROC NEAR ; новый обработчик критической
; ошибки
iret ; вероятно будут выполнены ка-
; кие-либо действия относительно
; ошибки (может быть отказ вызова)
NewInt24 ENDP
_text ENDS
----------------------------------------------------------------
- 4-43 -
Обращение к глобальным переменным
Как минимум, Ваша TSR, устанавливая личную DTA и становясь
текущей программой, будет записывать текущие DTA и PSP. Адрес DTA
и адрес текущего PSP записывается в глобальные переменные DOS. К
переменным можно обращаться непосредственно, но их размещение мо-
жет изменяться в зависимости от версии DOS. Для получения и уста-
новки адреса DTA и адреса текущего PSP имеются служебные функции
BIOS. В этом месте последовательности повторной активации необхо-
димо определить, безопасно ли делать запросы к BIOS и защитить
себя от break и критических ошибок. Использование для этих целей
служебных функций BIOS позволяет не заботиться о положении этих
переменных в конкретной версии DOS.
Листинг 4-29. Обращение к глобальным переменным
----------------------------------------------------------------
BKGDTA DB 80h DUP(0) ; минимальный размер DTA
BKGPSP DW 0 ; программа инициализации запоминает
; здесь значение PSP
DOSPSP DW 0 ; здесь мы будем сохранять PSP и DTA
DOSDTA DW 0,0 ; прерванной программы
BKGSetPSP PROC NEAR
pushr ; сохранение изменяемых регистров
mov ah,62h ; запрос DOS о текущем PSP
int 21h
mov DOSPSP,bx ; сохранение текущего PSP
mov ah,50h ; сообщение DOS об использовании но-
; вого PSP
mov bx,BKGPSP
int 21h ; недокументирована
popr
ret
BKGSetPSP ENDP
BKGSetDTA PROC NEAR
pushr
mov ah,2fh
int 21h
mov DOSDTA,bx ; запись адреса DTA
mov DOSDTA+2,es
lea dx,BKGDTA ; ds:dx <== новая DTA
mov ah,1ah
int 21h
popr
ret
BKGSetDTA ENDP
----------------------------------------------------------------
Фоновая обработка с использованием прерывания int 28h
Финальной частью изучения TSR является фоновая обработка.Эта
возможность является недокументированной, и поэтому недостаточно
понятной. При правильном использовании, пока выполняется другая
программа,TSR может выполнять запросы к BIOS. Программа PRINT.COM
- 4-44 -
использует эту возможность для чтения блоков файла. Система под-
готовки текстов может использовать эту возможность для сохранения
файла параллельно с редактированием переднего плана, а средство
ведения электронных таблиц при фоновой обработке может выполнять
длинные вычисления.
DOS обеспечивает в помощь программисту некоторые "зацепки",
но для их использования ему необходимо довольно много поработать.
Такими "зацепками" для фоновой обработки являются программы ISR