На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 4 / Фоновая обработка с использованием прерывания int 28h Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Фоновая обработка с использованием прерывания int 28h

Финальной частью изучения TSR является фоновая обработка. Эта возможность является недокументированной, и поэтому недостаточно понятной. При правильном использовании, пока выполняется другая программа,TSR может выполнять запросы к BIOS. Программа PRINT.COM использует эту возможность для чтения блоков файла. Система подготовки текстов может использовать эту возможность для сохранения файла параллельно с редактированием переднего плана, а средство ведения электронных таблиц при фоновой обработке может выполнять длинные вычисления.


DOS обеспечивает в помощь программисту некоторые "зацепки", но для их использования ему необходимо довольно много поработать. Такими "зацепками" для фоновой обработки являются программы ISR критической секции, критической ошибки и int 28h. Довольно часто программы много времени расходуют на ожидание ввода информации. Путем захвата прерывания int 28h TSR может использовать для своих целей циклы центрального процессора, которые иначе бы тратились на ожидание ввода информации. В связи с тем, что эту возможность также могут использовать и другие программы TSR, то ISR прерывания int 28h, когда она выполняется, должно образовывать цепочку с предыдущей ISR.


ISR прерывания int 28 запускает TSR только в том случае, если прикладная программа переднего плана использует функцию DOS в/в символов. TSR, которая нуждается в фоновой работе, обычно "захватывает", кроме того, одно или два прерывания таймера. ISR таймера обеспечивает TSR доступ к процессору даже в том случае, если приоритетная прикладная программа является программой с интенсивными вычислениями, или не использует функции в/в символов.


Написание ISR int 28h является достаточно простым делом. Новая ISR сначала вызывает старую ISR и затем увеличивает значение того же самого флажка BusyFlag (флажок "занято"), используемого программами ISR прерываний int 8, int 9 и дискового в/в. Если результат не нулевой, то выполняются некоторые непрерываемые функции. Так как эта ISR должна получать управление только тогда, когда доступ к диску безопасен, увеличение должно всегда вырабатывать нулевой результат. Тем не менее, необходимо быть готовым к блужданиям по прерываниям int 28h. После повторной активации TSR программа ISR уменьшает значение флажка BusyFlag и возвращает управление в DOS. Заметим, что не нужно выполнять проверку флажка критической ошибки: поскольку выполняется запрос int 21h, то Вы знаете, что он установлен; однако он всегда сохраняется для выполнения запросов int 21h, номер функции которых больше значения 0ch. Для предохранения TSR от повторной активации при нажатии горячего ключа или при прерывании таймера необходимо увеличить значение флажка BusyFlag.



            Листинг 4-30. Подпрограмма обслуживания прерывания int 28h
         ----------------------------------------------------------------

         OldInt28   DD                ; здесь программа инициализации за-
                                      ; писывает адрес старой ISR
         BusyFlag   DB                ; защита нереентерабельных секций
                                      ; программы
         Int28ISR   PROC
         Int28Exit0:
                    dec  cs:BusyFlag  ; освобождение Вашей блокировки и
                    iret              ; возврат
         NewInt28:
                    pushf             ; имитация прерывания
                    call cs:OldInt28  ; диспетчирование оригинальной
                                      ; программы
                    inc  cs:BusyFlag  ; попытка снять блокировку
                    jg   Int28Exit0   ; если больше -- есть непрерываемые
                    call BKGResume    ; диспетчирование фоновой задачи
                    dec  cs:BusyFlag  ; снятие блокировки
                    iret              ; и возврат
         Int28ISR   ENDP
         ----------------------------------------------------------------

Процесс повторной активации TSR довольно прост: сохраните все регистры в текущем стеке и переключитесь на личный стек TSR. Большинство фоновых TSR выполняется короткое время и затем переводят сами себя в состояние ожидания. Обычно они сохраняют регистры в своих собственных стеках и возвращают управление в прерванную программу. Как часть последовательности повторной активации восстанавливайте регистры, сохраненные стеками TSR, когда они переводятся в состояние ожидания.


Программа PRINT.COM во время выполнения последовательности действий при своей повторной активации, увеличивает значение флажка критической секции. Эта утилита выполняет довольно необычные действия. Она обходит DOS и непосредственно вызывает драйвер устройства печати. Вероятно, увеличение значения флажка критической секции устраняет проблемы возможного повторного входа в драйвер устройства. Если Ваша TSR осуществляет непосредственный доступ к драйверу, то, по всей видимости, очень полеэно подражать действиям программы PRINT.COM.


Далее, установите свои собственные драйверы прерывания и критической ошибки, сделайте текущим PSP для Вашей TSR, и переключитесь на личную DTA. TSR, из которой была выбрана следующая подпрограмма, поддерживает как активацию горячего ключа, так и активацию фоновой обработки. Если повторная активация выполняется в ответ на нажатие горячего ключа, то необходимо сохранить содержимое текущего изображения на экране дисплея и выключить из работы буфер опережающего ввода информации с клавиатуры. Здесь сделано предположение о том, что любые клавиши в буфере опережающего ввода информации с клавиатуры были нажаты для предыдущей текущей программы и внесут только путаницу в повторную активацию TSR. Инструкция возврата управления передает управление TSR. По завершении работы TSR будет вызывать подпрограмму BKGSuspend (перевод в состояние ожидания для фоновой работы).


Коды, обеспечивающие ожидание, немного странны. TSR, использующая эти коды, периодически вызывает BKGSuspend. При определенных условиях BKGSuspend отправляет TSR на задний план, а в других случаях она ничего не делает. Пользователь может пожелать активизировать TSR с заднего плана путем нажатия горячего ключа. Если TSR, выполняющаяся на переднем плане, вызывает подпрограмму BKGSuspend, то эта подпрограмма проверяет буфер опережающего ввода информации с клавиатуры на наличие особой клавиши (BGCombo), нажатие которой отправляет ее на задний план. Если в буфере этой клавиши нет, то подпрограмма BKGSuspend игнорирует запрос на приостановку. Если клавиша BGCombo в буфере обнаружена, или если в настоящий момент TSR выполняется на заднем плане, то она перестает быть активной.


Приостановка выполняется по шагам, аналогично активации, но в обратном порядке. Подпрограмма BKGSuspend восстанавливает сохраненные DTA и PSP, восстанавливает драйверы прерывания и критической ошибки, сохраняет текущие регистры, восстанавливает экран (SCRBackground), уменьшает значение флажка критической секции, переключает стеки, восстанавливает индексные регистры и изменяет переменную PGMState. Инструкция RET в конце подпрограммы BKGSuspend возвращает управление в ISR, которая активизирует TSR. Если TSR выполнялась на заднем плане, то подпрограмма SCRBackground не выполняет переключение экрана.



                    Листинг 4-31. Перевод в состояние ожидания
                            и возобновление работы TSR
         ----------------------------------------------------------------

         SuspendResume      PROC    NEAR
         AltF10      EQU    113           ; расширенный код ASCII для
                                          ; клавиши ALT F10
         BGCombo     EQU    AltF10 SHL 8  ; LSB расширенного ASCII=0
         BKG_C_FG    EQU    1
         BKG_C_BG    EQU    2
         SaveStack   STRUC
         rSP         DW     0
         rSS         DW     0
         SaveStack   ENDS
         switch      MACRO  sstack,dstack ;; переключение стеков
                     cli                  ;; запрещение прерывания во
                                          ;; время переключения стеков
                     mov    sstack.rSS,SS ;; запись текущего стека
                     mov    sstack.rSP,SP
                     mov    SS,dstack.rSS ;; установка нового стека
                     mov    SP,dstack.rSP
                     sti                  ;; разрешение прерываний
                     ENDM
         _text       SEGMENT BYTE PUBLIC 'code'
         PgmState    DB     0             ; сохранение дорожки состояния
                                          ; программы
         InDosFlag   DD     0             ; здесь программа инициализации
                                          ; сохраняет адрес флажка крити-
                                          ; ческой секции
         OldStack    SaveStack <>         ; стек прерванной программы
         BKGStack    SaveStack <>         ; стек TSR. Устанавливается
                                          ; программой инициализации
         BKGResume:
                     call   BKGSaveAll    ; сохранение всех регистров в
                                          ; текущем стеке
                     cld                  ; флаг начального направления
                     mov    ax,cs
                     mov    ds,ax         ; ds <== программный сегмент
                     switch OldStack,BKGStack ; переключение на стек
                                          ; заднего плана
                     call   BKGRestoreAll ; восстановление регистров
                                          ; заднего плана
                     pushr  
                     les    di,InDosFlag  ; es:di <== флаг входа в DOS
                     inc    BYTE PTR es:[di] ; установка флага входа в
                                          ; DOS
                     popr   
                     call   BKGNewErrHndlr ; установка своих собственных
                                           ; драйверов критической ошиб-
                                           ; ки и прерывания
                     call   BKGSetPSP      ; изменение PSP
                     call   BKGSetDTA      ; изменение DTA
                     cli
                     cmp    PopupPending,0 ;;; ожидание popup?
                     jz     _br0           ;;; если 0 -- нет
                     dec    PopupPending   ;;; уменьшение на 1
                     mov    PgmState,BKG_C_FG ;;; перевод программы на
                                           ;;; передний план
                     call   SCRForeground  ;;; перевод экрана
                     call   BKGBufFlush    ;;; выключение буфера клавиа-
                                           ;;; туры
         _br0:       sti
                     ret
         BKGSuspend:
                     cmp    PgmState,BKG_C_FG ; выполнение на переднем
                                              ; плане?
                     jl     _bs0              ; если меньше -- задний
                                              ; план
                     jg     _bs2              ; если больше -- инициали-
                                              ; зация (игнорирование
                                              ; приостановки)
         ;
         ; Текущее выполнение на переднем плане. Проверка нажатия
         ;                           клавиши
         ;
                     push   ax             ; сохранение текущего значе-
                                           ; ния ax
                     xor    ah,ah          ; ah <== 1 (проверка состояния
                     inc    ah
                     int    16h            ; выдача запроса
                     jz     _bs1           ; если 0 -- нет доступного
                                           ; символа
                     cmp    ax,BKCombo     ; это символ заднего плана?
                     jnz    _bs1           ; если не 0 -- нет
                     xor    ah,ah          ; ah <== 0 (запрос чтения)
                     int    16h            ; удаление символа из буфера
                     pop    ax             ; восстановление ax
         ;
         ; Выполнение на заднем плане и запрос приостановки.
         ;
         _bs0:       call   BKGRestoreDTA  ; восстановление DTA
                     call   BKGRestorePSP  ; восстановление PSP
                     call   BKGRestoreErrHndlr ; восстановление старых
                                           ; драйверов критической ошиб-
                                           ; ки и прерывания
                     call   SCRBackground  ; восстановление экрана
                     call   BKGSaveAll     ; сохранение регистров зад-
                                           ; него плана
                     les    di,InDosFlag   ; es:di <== адрес входа в DOS
                     dec    BYTE PTR es:[di] ; уменьшение флажка входа в
                                           ; DOS
                     switch BKGStack,OldStack ; изменение стеков
                     call   BKGRestoreAll  ; восстановление регистров
                     mov    cs:PgmState,BKG_C_BG ; программы на заднем
                                           ; плане
                     ret                   ; возврат
         _bs1:       pop    ax             ; восстановление начального
                                           ; значения ax
         _bs2:       ret                   ; возврат
         SuspendResume      ENDP
         _text              ENDS
         ----------------------------------------------------------------

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz