Мультизадачность.

Глава 12. Использование шлюзов задачи.

        В этой главе приводится пример реализации мультизадачной системы, в которой переключение задач происходит через прерывания. Для этого обработчик исключения прерывания таймера (IRQ 0) реализован в виде отдельной задачи и переключение задач производится по прерыванию таймера (примерно 18 раз в секунду).
        В дескрипторе TSS прерванной задачи флаг занятости B остаётся установленным и одной из функций задачи "Main", переключающей две другие задачи "2" и "3", является явный сброс это флага в дескрипторе TSS только что прерванной задачи.
        Задачи 2 и 3 не "подразумевают" о том, что их прерывают, они не передают управление другим задачам и такой вариант работы ОС является наиболее общим видом мультизадачной системы.
        Пример, приведенный в конце главы, использует следующую схему работы:
  • Определяютcя 4 задачи: Main, 2, 3 и Timer; задача Main производит инициализацию мультизадачности, задачи 2 и 3 являются рабочими задачами, а Timer обеспечивает поочерёдное переключение между задачами 2 и 3.
  • Задача Main разрешает прерывание от таймера (которое было запрещено при инициализации примера) и зацикливается. Больше никаких действий эта задача выполнять не будет - как только сработает прерывание таймера, управление в задачу Main уже не вернётся.
  • В примере реализована очередь из двух задач Task_list, представляющая собой два далёких адреса перехода на задачу 2 и 3, расположенных последовательно один за другим. Переменная Task_number хранит номер текущей задачи: Task_number = 0/1 - текущей задачей является задача "2" / "3".
  • Обработчик прерывания таймера изменён следующим образом:
  • прерывания запрещены ещё при построении контекста задачи. Это гарантирует, что во время работы задачи Timer, она не будет прервана другими аппаратными прерываниями. С другой стороны, простота самой задачи гарантирует то, что во время выполнения кода задачи не возникнет исключения;
  • после посылки команды конца прерывания, задача Timer, с помощью переменной Task_number, определяет текущую задачу и сбрасывает в её дескрипторе TSS флаг занятости B;
  • в конце цикла работы задачи Timer, управление передаётся следующей задаче в очереди задач. Для передачи управления используется команда FAR JMP.

            Таким образом, схема работы задач в такой системе получается следующей:

    Timer_TSS → TSS_1 → Timer_TSS → TSS_2 → Timer_TSS → TSS_1 → Timer_TSS → TSS_2 → ...

            или так:

    	[ [ Timer_TSS -> TSS_i ] = n раз  ] = ? раз,
    

    где "n" означает число задач в системе, а "?" - то, что этот цикл повторяется любое число раз.

            В такой схеме только один "минус" - то, что при каждом переключении задач предварительно запускается задача Timer, что понижает производительность системы, однако, наличие такой интерфейсной задачи позволяет операционной системе не только управлять переключением задач, но и выполнять следующие действия:
  • Обрабатывать таймер - менять соответствующим образом переменные времени, даты и некоторые системные счётчики, зависящие от времени.
  • Использовать простую структуру рабочих задач и простой способ управления ими, что повышает надёжность и защищённость системы (например, в ОС можно реализовать переключение задач только через очередь и только такой интерфейсной задачей (Timer) и тогда можно запретить задачам самостоятельно вызывать другие задачи).
  • Менять дополнительный контекст задачи, например, загружать контекст модуля FPU, MMX и/или XMM до того, как задача явно запросит систему об этом (через исключение), что сэкономит время и, соответственно, повысит производительность системы.
  • Можно перед запуском следующей в очереди задачи проводить некоторые проверки, позволяющие повысить производительность системы. Так, например, задачи, находящиеся в состоянии "сна" (stand by) можно пропускать; также можно пропускать задачи, ожидающие событий от устройств ввода, но ещё не получивших нужные данные (например, пропустить задачу, ожидающую ввода с клавиатуры, если с клавиатуры ничего не было введено).

            Предлагаемый вашему вниманию пример похож на предыдущий, но имеет следующие дополнения:
  • В GDT добавлен дескриптор "Timer_TSS", описывающий контекст задачи обработчика прерывания таймера.
  • Установка дескриптора TSS для Timer_TSS производится вместе с остальными дескрипторами TSS:

    ; Устанавливаем дескрипторы трёх основных TSS: mov bx,offset GDT + Main_TSS mov eax,ebp mov edx,67h mov cx,10001001b call set_descriptor ; Main_TSS add eax,104 call set_descriptor ; TSS_2 add eax,104 call set_descriptor ; TSS_3 ; Устанавливаем дескриптор Timer_TSS: mov bx,offset GDT + Timer_TSS add eax,104 call set_descriptor ; Timer_TSS
  • Установка мультизадачности также немного отличается от предыдущего примера:

    ; Установка мультизадачности xor di,di ; Это будет первая задача. mov eax,cr3 mov ecx,202h ; EFLAGS задачи с установленным флагом ; прерываний - они будут разрешены. mov edx,100 ; ESP 1-й задачи. mov bp,0 ; LDT у 1-й задачи нет. call set_TSS add di,104 ; Это будет вторая задача. lea ebx,second_task_entry_point ; EIP задачи. mov edx,200 ; ESP 2-й задачи. mov bp,offset LDT_area + 64 shl ebp,16 mov bp,LDT_2 ; LDT 2-й задачи. call set_TSS add di,104 ; Это будет третья задача. lea ebx,third_task_entry_point ; EIP задачи. mov edx,300 ; ESP 3-й задачи. mov bp,offset LDT_area + 128 shl ebp,16 mov bp,LDT_2 ; LDT 3-й задачи. call set_TSS add di,104 ; Это задача таймера. lea ebx,Timer_task_entry_point ; EIP задачи. mov ecx,10b ; EFLAGS задачи таймера - прерывания будут ; запрещены. mov edx,400 ; ESP задачи таймера. mov ebp,0 ; LDT у задачи таймера нет. call set_TSS
    ; Запускаем первую задачу: mov ax,Main_TSS ltr ax ; Чистим Busy flag Main_TSS mov bx,offset GDT + Main_TSS and byte ptr [ bx + 5 ],11111101b ; Переход на Main_TSS db 0eah dw 00 dw Main_TSS
  • Вот так задача Main инициализирует в примере мультизадачность с прерыванием по таймеру:

    ; Main_TSS: mov ax,Data_Selector mov ds,ax ; Установка Busy flag Main_TSS mov bx,offset GDT + Main_TSS or byte ptr [ bx + 5 ],10b mov text_color,1fh lea bx,fst_task_msg mov dx,0600h call put_zs mov Task_number,0 ; Разрешаем прерывания от таймера: in al,21h and al,11111110b out 21h,al ; Зацикливаем эту задачу. Теперь по прерыванию таймера управление ; будет передано в задачу Timer_TSS и больше сюда не возвратится. mtss_1: jmp mtss_1
    second_task_entry_point: mov text_color,1ah lea bx,snd_task_msg mov dx,0700h call put_zs xor eax,eax step_1: mov text_color,1ah call put_dd_num inc eax sub dl,8 jmp step_1
    third_task_entry_point: mov text_color,1eh lea bx,trd_task_msg mov dx,0800h call put_zs xor eax,eax ttep_1: mov text_color,1eh call put_dd_num dec eax sub dl,8 jmp ttep_1

            Обратите внимание, что рабочие задачи (это "2" и "3") обе работают в бесконечном цикле и не передают управление другим задачам. Переключение задач действительно происходит по таймеру.

  • Вот так выглядит обработчик прерывания от таймера; этот код является кодом задачи Timer:

    IRQ_0_handler macro Timer_task_entry_point: push ax mov al,20h out 20h,al pop ax lea bx,Task_List mov al,Task_number mov dl,al ; Временно сохраняем это значение. cmp al,1 je timer_1 inc al add bx,4 jmp timer_2 timer_1: dec al timer_2: mov Task_number,al ; Очистка флага занятости у прерванной задачи: ; 1. Вычисляем дескриптор TSS прерванной задачи. lea si,GDT mov dh,0 shl dx,3 ; DX = DL * 8 add dx,TSS_2 ; Теперь DX равен селектору: ; TSS_2, если Task_number был равен 0 ; TSS_3, если Task_number был равен 1 add si,dx ; DS:SI указывают в GDT на содержимое ; дескриптора TSS. ; 2. Сброс флага занятости. and byte ptr [ si + 5 ],11111101b ; Переключение на новую задачу: jmp dword ptr [ bx ] jmp Timer_task_entry_point endm
  • И, наконец, прекращение работы программы произойдёт по нажатию клавиши Esc, для чего ещё в прошлых примерах соответствующем образом изменён обработчик клавиатуры.

            Сам пример доступен здесь - файлы examp_11.asm, examp_11.com, pmode_11.lib и init.lib, - в архиве examp_11.zip (20'501 байт).

    Оглавление Вопросы? Замечания? Пишите: sasm@narod.ru

      Copyright © Александр Семенко.
    TopList

    Hosted by uCoz