Как пользователь может создавать подпрограммы в языке управления заданиями windows

Cкачать: УРОК № 22 Тема. Стандартные подпрограммы и подпрограммы пользователя. Создание и вызов подпрограмм

УРОК № 22

Тема.
Стандартные подпрограммы и подпрограммы пользователя. Создание и вызов
подпрограмм

Цели:

сформировать
понятие:


подпрограммы;

формировать
умения:

— работать
в среде программирования;


создавать проект и отлаживать его;

— изменять
значения свойств элементов управления;


редактировать код обработчиков событий;


использовать среду программирования для создания проектов;


создавать проект для собственного использования;

— четко и
лаконично выражать мысли;

— делать
выводы;

воспитывать:


внимательность, дисциплинированность во время работы на ПК.

Тип урока: усвоение
новых знаний.

Базовые
понятия и термины: класс, метод, подпрограмма.

Структура
урока

1.
организационный этап. . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2
мин

2.
Проверка домашнего задания. . . . . . . . . . . . . . . . . . 2-3 мин

III.
Актуализация опорных знаний. . . . . . . . . . . . . . . . . . . . . 2-5 мин

IV.
Мотивация учебной деятельности. . . . . . . . . . . . . . . . . 1-3 мин

V.
Восприятие и осознание нового материала. . . . 15-20 мин

VI.
Первичное закрепление знаний. . . . . . . . . . . . . . . . . . . 15-20 мин

VII.
Подведение итогов урока. . . . . . . . . . . . . . . . . . . . . . . . 3-5 мин

VIII. Домашнее
задание. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2 мин

Ход урока

1.
ОРГАНИЗАЦИОННЫЙ ЭТАП

Поздравление.
Подготовка класса к занятиям. Объявления темы,

цели и
задач урока.

2.
ПРОВЕРКА ДОМАШНЕГО ЗАДАНИЯ

III.
АКТУАЛИЗАЦИЯ ОПОРНЫХ ЗНАНИЙ

 Беседа с
элементами опроса

1. Как
создать проект?

2. С
помощью каких элементов пользователь может вводить данные

в
программу? выводить результат?

3. Какие
свойства элементов управления вы знаете?

IV.
МОТИВАЦИЯ УЧЕБНОЙ ДЕЯТЕЛЬНОСТИ

Учитель.
При создании программ иногда возникает необходимость повторно использовать
части кода. Если такая необходимость

возникает
несколько раз, код можно просто скопировать. Что же делай ты, когда код
необходим достаточно часто?

V.
восприятие и осознание НОВОГО материала

Подпрограмма
(subroutine) — часть программы, которая реализует определенный алгоритм и
позволяет обращаться к ней из разных частей за гальной (главной) программы.

Подпрограмму
часто используют для сокращения размеров

программ в
тех задачах, в процессе решения которых необходимо выполнять несколько раз
одинаковый алгоритм при разных значениях

параметров.
Операторы (команды), реализующие соответствующую под программу, записывают один
раз, а в необходимых местах размещают

операторы
передачи управления на эту подпрограмму.

Набор
наиболее употребляемых подпрограмм образует библиотеку состояние дартных
подпрограмм.

В
большинстве языков программирования высокого уровня подпрограммы

называют
процедурами и функциями. В зависимости от языка програ мирования, термины
«процедура» и «функция» могут различаться

(как
правило, процедурой называют подпрограмму, которая не возвращает

результата,
тогда как функция имеет результат и может использовать ся как часть выражения)
или рассматриваться как синонимы.

Учебный
материал объясняется на реальном примере.

Создать
проект решения задачи-Project-Function.

Вычислить:
ctgx.

В С#
отсутствует функция Ctg. Попробуем организовать ее вычисление, используя класс
с определенным методом вычисления

котангенса.

Код проекта

using
System;

using
System.Collections.Generic;

using
System.ComponentModel;

using System.Data;

using
System.Drawing;

using System.Linq;

using System.Text;

using
System.Windows.Forms;

namespace
Project_Function

{

publicpartialclassForm1
: Form

{

public Form1()

 {

Все уроки информатики. 11 класс.
Академический уровень. Часть 1 171

InitializeComponent();

 }

//
Объявления функции для вычисления ctg

publicstaticdouble
Ctg(double a)

 {

returnMath.Cos(a)/Math.Sin(a);

 }

publicdouble x, y;

publicvoid
button1_Click(object sender, EventArgs e)

 {

 x =
Convert.ToDouble(textBox1.Text);

 y = Ctg(x);

                                      textBox2.Text
= “” + y;

 }

}

}

Учащиеся
выполняют комплекс упражнений для снятия зрительной усталости (Вариант 1 или
2). Упражнения проводит староста класса (группы) или его заместитель.

VI.
ПЕРВИЧНОЕ ЗАКРЕПЛЕНИЕ ЗНАНИЙ

 Практическое
задание

Инструктаж
по технике безопасности.

Создайте
проект, который вычисляет корень квадратный числа, по касавши соответствующий
метод.

Инструктивная
карточка

1.
Запустить среду программирования.

2. Создать
проект Windows Forms с именем Project-Function2.

3.
Добавить необходимые объекты на форму, используя как образец

проект,
рассмотренный в ходе урока.

4.
Изменить свойства объектов.

5.
Написать код обработчиков событий.

6.
Запустить проект на выполнение и проверить его працездат ность.

7. Сохранить проект (C:11 form
ProjectsProject-Function2).

VII.
ПОДВЕДЕНИЕ ИТОГОВ УРОКА

Учитель
оценивает работу учеников на уроке.

VIII.
ДОМАШНЕЕ ЗАДАНИЕ

Проработать
конспект урока и соответствующий раздел учебника.

Функции и компоненты подсистемы JES2

Задания, поступающие в систему от различных источников, принимаются и
обрабатываются специальным компонентом z/OS, который называется подсистемой управления заданиями JES (Job Entry Subsystem)1Хотя слово entry часто переводят как <вводgt;, здесь его смысл следует трактовать шире.. JES
принимает задания (рис. 5.19), поступающие с входных устройств,
регистрирует их, осуществляет анализ и формирует очереди заданий, а
затем передает задания на выполнение базовой управляющей программе BCP.
После завершения выполнения задания и получения результатов от BCP, JES
формирует отчет по заданию (листинг), передает его пользователю или
выводит на указанные устройства. Чаще всего в установленных
конфигурациях z/OS используется базовый компонент управления заданиями
JES2, который и будет рассмотрен в данной главе. Альтернативой JES2
является опциональный компонент JES3, который в отличие от JES2 может
использоваться для централизованного управления заданиями в
многомашинной системе. Отметим, что JES2 работает в собственном
адресном пространстве и имеет статус подсистемы (использует специальный
SSIинтерфейс для взаимодействия с базовой управляющей программой
z/OS). Кроме того, JES2 поддерживает собственные языковые средства,
которые можно включать в текст задания (так называемые операторы JECL —
Job Entry Control Language) и применять в виде консольных команд
(системные команды JES2).

Назначение подсистемы управления заданиями

Рис.
5.19.
Назначение подсистемы управления заданиями

На рис. 5.20 представлена схема, иллюстрирующая основные этапы
обработки заданий после того, как они направлены в подсистему JES2

[
5.13
]
.

Этапы обработки заданий

Рис.
5.20.
Этапы обработки заданий

На этапе ввода (entry phase) осуществляется прием заданий, поступающих
в систему от различных источников. Пользователь может задействовать для
этих целей терминальные устройства, консоли, сетевые рабочие станции и
т.п., применяя консольные команды START, MOUNT, команды TSO/E LOGON и SUBMIT. Существует возможность формировать и направлять задания на
обработку из ранее запущенных программ и заданий. Поддерживается
возможность удаленного RJE (Remote Job Entry) и сетевого NJE (Network
Job Entry) ввода заданий, поступающих от узлов распределенной
вычислительной сети. JES2 контролирует все пути поступления заданий с
помощью специальных встроенных программ ввода INTRDR (Internal Reader).
Текст каждого поступившего задания (предложения JCL и JECL) и вложенные
в него входные данные пользователя (обозначаемые как набор данных
SYSIN) помещаются в специальный набор данных JES2, называемый «спул»
(spool).

Спул используется для временного хранения данных, связанных с
выполнением каждого поступившего в подсистему JES2 задания, и содержит:

  • JCL операторы задания и специальные операторы JES2 (JECL);
  • исходные данные, представленные во входном потоке (набор данных
    SYSIN);
  • выходные данные и сообщения, формируемые в процессе выполнения
    задания, и подготавливаемые для вывода в отчет (набор данных SYSOUT);
  • управляющая информация JES2;
  • сообщения для вывода в системный журнал SYSLOG.

На этапе ввода осуществляется регистрация задания, заключающаяся в
присваивании заданию уникального идентификатора (JobID) и занесении
учетной и статусной информации в специальный реестр JES2, получивший
название очередь заданий (JOBQUEUE). Помимо идентификатора, JOBQUEUE
содержит также значения класса, приоритета и текущего состояния
задания. Фактически все множество очередей, представленных на рисунке,
хранится в одной общей таблице JOBQUEUE. В этом случае выборка заданий
производится по значению кода текущего состояния, показывающего, на
каком этапе обработки задание находится в данный момент.

Все зарегистрированные задания поступают затем в очередь на следующий
этап обработки.

На этапе преобразования (conversion phase) сначала производится анализ
текста задания и трансляция его в специальный промежуточный код. Если
обнаружены синтаксические ошибки, формируется отчет SYSOUT, включающий
диагностические сообщения, и задание направляется на этап вывода, минуя
стадию выполнения. В процессе анализа при необходимости происходит
включение в текст задания и настройка параметров так называемых процедур JCL, вызываемых из внешних библиотек. Процедуры представляют
собой готовые блоки предложений JCL, предназначенные для решения
типовых пользовательских задач и хранящиеся в специальных наборах
данных — библиотеках процедур (на рисунке обозначены как PROC). JES2
располагает настраиваемым списком используемых стандартных библиотек
процедур (самая известная среди них — SYS1.PROCLIB). Пользователь также
имеет возможность указать собственный набор библиотек процедур с
помощью оператора JCLLIB.

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

На этапе выполнения (execution phase) ключевую роль играют системные
программы, получившие название инициаторов (initiators). Обычно
запускается несколько инициаторов одновременно, так чтобы один
инициатор обслуживал одну или несколько конкретных очередей заданий (по
значениям класса). Каждый инициатор работает в собственном виртуальном
адресном пространстве в соответствии со следующим алгоритмом:

  • инициатор формирует запрос к JES2 на получение нового задания из
    очередей обслуживаемых им классов;
  • JES2 анализирует очередь заданий (JOBQUEUE) и передает инициатору
    сообщение о выбранном в соответствии с приоритетом задании;
  • инициатор считывает из спула промежуточный код задания и входные
    данные (SYSIN), определяет, какие ресурсы необходимы для выполнения, и
    открывает соответствующие наборы данных, а также копирует в свое
    адресное пространство загрузочные модули вызываемых в задании программ;
  • инициатор последовательно передает управление программам задания,
    контролируя ход их выполнения и поступающие сообщения; реальное
    управление выполнением программ реализуется базовой управляющей
    программой (BCP);
  • при завершении задания (нормальном или аварийном) результаты работы
    программ передаются инициатором в набор данных SYSOUT спула, а задания
    поступают в очередь на стадию вывода.

Отметим, что в z/OS поддерживается два типа инициаторов: инициаторы JES
и инициаторы WLM. Инициаторы JES2 обычно запускаются автоматически при
инициализации системы в соответствии с настройками JES2 и назначаются
на обслуживание определенных классов заданий. Инициаторы WLM
запускаются динамически в зависимости от текущей нагрузки системы и в
соответствии с установленной политикой управления нагрузкой в целевом
режиме.

Важно подчеркнуть, что для большинства заданий не создаются новые
адресные пространства z/OS, поскольку их выполнение происходит в
адресных пространствах инициаторов. Исключение составляют задания
классов STC и TSU, которые не обрабатываются инициаторами. Для этих
классов JES2 самостоятельно создает отдельные адресные пространства для
каждого пользовательского сеанса TSO и каждой запускаемой процедуры, а
также обрабатывает поступающие сообщения.

На этапе вывода (output phase) JES2 формирует отчет о выполнении
задания в наборе данных SYSOUT в соответствии с требованиями и
характеристиками назначенного выходного класса и указанными в задании
атрибутами вывода. Выходной класс задания (всего доступно 36 классов,
кодируемых символами A-Z или цифрами 0-9) определяется пользователем с
помощью параметра SYSOUT оператора DD или оператора OUTPUT либо
назначается подсистемой JES2 по умолчанию. Классы служат для
группирования заданий с целью использования общих ограничений по выводу
отчетов и для целей управления, но никак не связаны с используемыми для
вывода устройствами. Подготовленные отчеты направляются в очередь на
стадию печати или задерживаются на этапе вывода, если для задания
установлен статус HOLD. Данный статус задается пользователем или
устанавливается JES2 для некоторого класса или группы заданий.
Дальнейшая обработка задержанных заданий производится по специальному
указанию оператора (пользователя).

На этапе печати (hardcopy phase) производится вывод подготовленного
отчета из набора данных SYSOUT на указанное пользователем или
установленное JES2 выходное устройство (принтер, узел сети и т.п.), и
задание передается в очередь на стадию завершения.

На этапе завершения (purge phase) JES2 осуществляет «очистку» спула и
очереди заданий от информации, связанной с выполненным заданием, и
формирует соответствующее сообщение.

Следует напомнить, что в z/OS существует специальный опциональный
компонент SDSF, предназначенный для просмотра параметров текущего
состояния всех запущенных в системе заданий и отчетов о выполнении, а
также предоставляющий возможность изменять некоторые параметры и
управлять ходом выполнения заданий динамически.

Структура пакетного задания JCL

Итак, прежде чем передать пакетное задание системе, пользователь должен
подготовить его текст на языке JCL. Обычно текст задания создается в
некотором наборе данных с помощью текстового редактора, откуда
специальными средствами пользовательского интерфейса его можно
направить на обработку в подсистему JES2. z/OS требует, чтобы для
представления заданий использовались только последовательные и
библиотечные наборы данных с параметрами RECFM=FB и LRECL=80. Текст
задания вводится, как правило, прописными буквами.

Задание состоит из последовательности управляющих предложений JCL (job
control statement)2Иногда предложения JCL называют <картами> задания (job cards), вспоминая о тех
временах, когда текст задания готовился на перфокартах. Оттуда, кстати, унаследовано
ограничение строки задания в 80 символов.
. Каждое предложение имеет следующую структуру:

//ИМЯ ОПЕРАТОР ОПЕРАНДЫ КОММЕНТАРИЙ

В первых двух позициях всегда (или почти всегда) указываются две косые
черты (знак слэш / ), которые являются главным отличительным признаком
предложений JCL.

Поле имя начинается с третьей позиции и служит для идентификации
представленного в предложении оператора. Фактически это метка, на
которую можно ссылаться из различных предложений задания или других
заданий. Имя может содержать не более восьми символов, включающих
латинские буквы, цифры и специальные знаки ( $ # @ ). Имя должно
начинаться с буквы или специального знака, русские буквы и пробелы
использовать нельзя. В некоторых специальных случаях применяют
составные имена, использующие в качестве разделителя точку. Пробел в
третьей позиции является признаком отсутствия имени.

Примеры правильных имен: STOUT1, SYSPRINT, IVANOV, IVAN#S

Примеры неправильных имен: 3DIAGNOZ (начинается с цифры), DIAGNOSTIKA
(содержит более восьми символов), ТОМ+И (содержит недопустимый символ И ).

Вслед за полем имени следуют другие поля, отделяемые друг от друга
одним или несколькими пробелами.

Таблица
5.4.
Основные операторы JCL

Оператор Назначение оператора
JOB Начало задания и режим выполнения задания
EXEC Начало шага задания, указание выполняемой программы или процедуры
DD Описание набора данных и используемых устройств
COMMAND Ввод системной (консольной) команды MVS или команды JES
PROC Начало процедуры и описание параметров процедуры
PEND Конец процедуры
JCLLIB Список библиотек для поиска процедур, указанных в задании
OUTPUT Параметры формирования отчета о выполнении задания (SYSOUT)
INCLUDE Имя раздела библиотеки, текст которого необходимо включить
в указанное место задания
CNTL/ENDCNTL Начало и конец блока управляющих параметров, передаваемых
программе во входном потоке
IF/THEN/ELSE/ENDIF Условное выполнение шагов задания (ветвление)
SET Инициализация или изменение значений символических параметров
/* Оператор ограничения данных, представленных во входном потоке
// Пустой оператор (конец задания)
//* Оператор комментария

Поле оператор определяет тип управляющего оператора JCL, который
задается одним из ключевых слов, представленных в таблица 5.4.
Назначение и использование основных операторов ( JOB, EXEC, DD ) будет
рассмотрено в данной главе.

Поле операнды предложения JCL содержит список разделенных запятыми
параметров, которые записывают вслед за именем оператора (через один
или несколько пробелов). С помощью параметров сообщают информацию,
необходимую для выполнения оператора. Различают позиционные и ключевые
параметры.

Позиционные параметры часто имеют произвольный формат записи, но всегда
указываются в строгой последовательности и всегда перед ключевыми
параметрами. Если позиционный параметр опускается, то запятая, которая
должна следовать за параметром, остается (исключение составляет случай,
когда опускается последний параметр в списке позиционных параметров).
Примеры записи позиционных параметров:

333,TEST,,0.8E-15 NEW,,DELETE

Ключевые параметры задаются с использованием предопределенных ключевых
слов в виде: ключевое_слово=значение. Например, CLASS=B, REGION=100M, COND=(1,LE). Последовательность записи ключевых параметров —
произвольная.

Отдельные параметры могут включать подпараметры, которые также задают в
виде списка, заключенного в апострофы или круглые скобки. Как и
параметры, подпараметры могут быть позиционными и ключевыми. Скобки или
апострофы опускаются, если в списке указывается один подпараметр.
Например:

DISP=(NEW,,DELETE) — позиционные подпараметры параметра DISP

DCB=(RECFM=FB,LRECL=80) — ключевые подпараметры параметра DCB

В поле комментарий предложения JCL помещают произвольную текстовую
информацию, поясняющую назначение или особенности использования
отдельных операторов. Отметим, что для этой цели может применяться
специальный оператор комментария //*. Этот текст не обрабатывается при
выполнении задания.

Поля предложений JCL не должны выходить за пределы 71-й позиции строки.
Если же текст предложения не умещается в одной строке, то его (кроме
предложения комментария //* ) разрешается продолжить на следующей. При
этом если необходимо перенести на следующую строку некоторые параметры
из списка, то следует соблюдать такие правила:

  1. Разрыв строки необходимо сделать точно в том месте, где
    располагается разделительная запятая списка параметров.
  2. В следующей строке в позициях 1 и 2 нужно указать символы //.
    Продолжить ввод списка параметров, начиная не ранее 4-й, но не позднее
    16-й позиции строки.

    Вот как выглядит запись многострочного предложения JCL:

    //OUT DD UNIT=SYSDA,VOL=SER=UB1,
    // DISP=NEW,SPACE=(1000(5,4)),
    // DSN=&&TEMP1

Исключением из этого правила является ситуация, когда перенос требует
«разорвать» параметр, заключенный в апострофы. В этом случае следует
вводить текст предложения до 71-й позиции включительно, а продолжение
располагать точно с 16-й позиции следующей строки.

Структуру задания в z/OS схематично можно представить в виде
последовательности операторов (рис. 5.21). Первым всегда указывается
оператор задания JOB, который отмечает начало задания. Непосредственно
за оператором JOB могут следовать другие операторы ( DD, JCLLIB, OUTPUT ), с помощью которых описывают общие ресурсы задания в целом
(наборы данных, библиотеки процедур, параметры вывода результатов).

Структура задания

Рис.
5.21.
Структура задания

Последующие операторы задания группируются по шагам или пунктам. Шаг
(пункт) задания
(job step) — это последовательность операторов JCL,
начинающаяся с оператора EXEC и включающая некоторое количество иных
операторов (в основном DD ). Оператор EXEC (его называют иногда
оператором шага задания) устанавливает, какую программу (загрузочный
модуль) или процедуру JCL необходимо выполнить. С помощью операторов DD
в шаге задания описывают наборы данных и/или устройства, используемые
при выполнении указанной в операторе EXEC программы (процедуры). Шаги
задания выполняются строго последовательно. Однако есть возможность
пропуска (невыполнения) некоторых шагов в зависимости от результатов
работы предыдущих шагов с помощью операторов IF/THEN/ELSE или параметра COND операторов JOB и EXEC. Общее количество шагов задания не может
превышать 255, включая шаги всех вызываемых в задании процедур.

Далее приводится обзор основных операторов языка управления заданиями,
который, однако, не претендует на полноту и не может служить заменой
стандартной документации
[
5.14
]
,
[
5.15
]
. Многие операторы и особенности их
применения представлены без некоторых деталей, которые могут
понадобиться при практическом использовании JCL. При описании формата
операторов используются привычные мнемонические правила:

  • информация, заключенная в квадратные скобки, является необязательной
    и может быть опущена;
  • символ | используется для указания альтернативных значений, из
    которых следует выбрать одно.

Нужно отметить, что язык JCL достаточно подробно описан в отечественной
литературе
[
5.16
]
,
[
5.17
]
,
[
5.18
]
, в том, правда, виде, в каком он сложился к
началу 90-х годов.

Windows

интегрированная
программа.

Под управлением оболочки Windows
могут работать не только специальные
программы, разрабо­танные для
эксплуатации
в
с
реде
Windows
(Windows-приложения), но
и «обычные» программы, работающие
в среде
DOS, т.н.
DOS-приложения (DOS-прикладные
программы). Оболочка
Window
обеспечивает эффективный и комфортабельный
обмен информацией между отдельными
программами, выполняемыми под ее
управлением. Здесь речь в первую очередь
идет о
Windows-пpилoжeнияx.
С понятием
интегрированности связывают обычно
также возможность совместного
использования ресурсов компьютера
различными прог­раммами. Так, к примеру,
принтер, подключенный к компьютеру,
может с одинаковым успехом использоваться
всеми программами на конкурентной
основе. Причем все операции, связанные
с необходимостью перекодировок, смен
драйверов (например, при переходе от
печати текстов к выводу иллюстраций)
берет на себя оболочка.

Большинство
пользователей привлекает в среде
Windows не
только и не столько комфортабельность
самой оболочки, сколько специфика
ре­ализованных в этой среде приложений.
Особенности реализации в среде Windows
даже знакомых пользователям по работе
в
DOS прикладных
программ (приложений)
практически позволяют рассматривать
Windows-версии
этих программ как совершенно новые
продукты.

Работа в
o6oлочке
Windows
и в
Windows-приложениях
предполагает своеобразную перестройку
«образа жизни». «Жизнь»
пользователя в среде ‘Windows
сопряжена с «мышиным» управлением,
обменами данными между отдельными
программами и параллельным выполнением.
Стандартизация интерфейсов отдельных
Windows-приложений
позволяет легко переходить от одного
приложения к другому, не начиная каждый
раз с нуля (хотя бы в плане способов и
средств управления).

зафиксировать
курсор

кнопкой мыши
— и операция
выполняется. С помощью того же манипулятора
можно перемещать пиктограммы и окна
по экрану, менять их размер, открывать
и закрывать их
— и все
это при минимальном использовании
клавиатуры для ввода каких бы то ни
было директив. Кроме того, для любителей
традиционного интерфейса
DOS реализована
возможность выхода на этот уровень.
При разработке графического интерфейса
Windows не
последнюю роль играли и эргономические
соображения: учтены требования к
цветовой гамме, сочетаниям цветов,
шрифтам, формам и размерам пиктограмм
и окон. По сравнению с некоторыми другими
пакетами внешнее оформление оболочки
Windows может
быть признано «спар­танским»
вследствие отсутствия излишеств и за
деловой стиль. Понятие
«графически-ориентированный»
включает в себя для
Win­dows
также и соответствие изображения на
экране последующему изображению на
твердой копии (распечатке). В этом плане
можно считать, что в оболочке
Windows
реализован принцип
WYSIWYG (
What
Yon See Is What You Get

=
To, что Вы
видите, то и получаете), до сих нор бывший
привилегией относительно небольшого
числа программ- С помощью
TrueType-шрифтов
этот принцип нашел в рамках
Windows
3.1 свое
дальнейшее развитие.

Windows
обеспечивает независимый
запуск
и
параллельное
выпол­нение нескольких программ.

Большинство других оболочек и операционных

В фирменной поставке
пакета Windows
находится несколько при­ложений. Все
они объединены в группу
Accessories
(аксессуары, инстру­менты). Это небольшие
по размеру и возможностям прикладные
програм­мы, составляющие «джентльменский
набор» пользователя. Им далеко до
профессиональных специализированных
пакетов. Но они прекрасно ил­люстрируют
возможности оболочки и обеспечивают
некоторый мини­мальный сервис. Более
того, весьма полезно начинать знакомство
с серь­езными пакетами именно с
соответствующих средств этой группы.
Так, например, поработав некоторое время
с текстовым редактором
Write,
в дальнейшем можно легко перейти к
использованию таких профессиональ-ных
пакетов обработки текстов, как
Word
для
Windows, Lotus
Ami Professional, WordPerfect
для
Windows’
т.п.
Кроме того, в приложениях из группы
Accessories
реализованы многие новинки, характерные
именно для последней версии
3.1 оболочки
Windows (работа с объектами,
новые шрифты…).

Windows
95

Объектно-ориентированный
подход

При создании
Windows
95 фирма
Microsoft в
полной мере реализо­вала
объектно-ориентированный подход.
Поскольку именно он лег в основу новой
операционной системы, вначале скажем
несколько слов о том, что такое ориентация
на объекты.

Понятие
«объектно-ориентированный» возникло
в программиро­вании сравнительно
недавно. Когда вычислительная мощность
ма­шин была невысока, о создании
объектно-ориентированных сис­тем не
могло быть и речи. Основой всего был
программный код. Программисты записывали
последовательности команд для выпол­нения
тех или иных действий над данными,
которые оформлялись в модули и процедуры.
Для работы с каждым объектом создавалась
своя процедура.

Объекты,
их свойства и

методы

Постепенно с
увеличением производительности
вычислительных систем процедурный
подход начал заменяться объектным. На
пер­вое место выдвинулся объект, а не
код, который его обрабатывает. На уровне
пользователя объектный подход выражается
в том, что интерфейс представляет собой
подобие реального мира, а работа с
машиной сводится к действиям с привычными
объектами. Так, пап­ки можно открыть,
убрать в портфель, документы
— просмотреть,
исправить, переложить с одного места
на другое, выбросить в корзину, факс или
письмо
— отправить
адресату и т. д. Понятие объекта оказалось
настолько широким, что до сих пор не
получило строгого определения.

Объект, как и в
реальном мире, обладает различными
свойствами. Программист или пользователь
может изменять не все свойства объектов,
а только некоторые из них. Можно изменить
имя объек­та, но нельзя изменить объем
свободного места на диске, который также
является его свойством. Свойства первого
типа в языках про­граммирования носят
название
read/write (для
чтения и записи), а свойства второго

read only
(только для чтения).

Метод
— это
способ воздействия на объект. Методы
позволяют со­здавать и удалять объекты,
а также изменять их свойства. Напри­мер,
для того чтобы нарисовать на экране
точку, линию или плоскую фигуру,
составляются разные последовательности
кодов или програм­мы. Пользователь,
однако, применяет для отображения этих
объек­тов один метод
Draw(
), который
содержит коды для отображения всех
объектов, с которыми он работает. За
такое удобство приходится пла­тить
тем, что объектно-ориентированные
системы могут работать только на
достаточно мощных вычислительных
установках.

Процедурный подход
в ранних ОС

До настоящего
времени во всех операционных системах
преобла­дал процедурный подход. Для
того чтобы произвести в системе
ка­кое-либо действие, пользователь
должен был вызвать соответству­ющую
программу (процедуру) и передать ей
определенные пара­метры, например,
имя обрабатываемого файла. Программа
выпол­няла над файлом указанные
действия и заканчивала работу. При этом
пользователь в первую очередь имел дело
с задачей обработки документа, а затем
уже с самим документом. В давние времена,
когда ЭВМ не были персональными,
пользователь описывал дейст­вия,
которые должна была выполнить задача,
на некоем странном языке, называемом
языком управления заданиями
(JCL—Job
Con­trol Language).

С появлением
терминала язык управления заданиями
упростился и постепенно превратился в
командную строку, однако на первом месте
все равно находилась процедура обработки
документа, а сам документ играл
вспомогательную роль.

Следующим этапом
упрощения работы с машиной стал создание
различного рода операционных оболочек
(сначала текстовых),которые «спрятали»
от пользователя командную строку
DOS. Ввод
последовательности символов, из которой
состоит команда опера­ционной системы,
свелся к нажатию одной функциональной
кла­виши или щелчку мыши. Самой
распространенной из таких «надстро­ек»
над операционной системой стала оболочка
Norton Commander,

Однако основным
«инструментом» пользователя все еще
оставалась клавиатура. Качественный
переход произошел после того, как
поя­вились графические оболочки.
Теперь пользователь в основном ра­ботает
с устройством указания, таким как мышь,
трекбол или план­шет, а не с клавиатурой
(разумеется, это не относится к работе
внут­ри самих приложений, например,
в текстовых редакторах). Ему не нужно
помнить почти никаких команд операционной
системы. Для того чтобы запустить
приложение, достаточно щелкнуть мышью
на его изображении или на «значке»
(автор предпочитает называть его
пиктограммой).

От
процедурного подхода к объектно-ориентированному

В начале 90-х гг.
процедурный подход все еще преобладает,
однако намечаются и некоторые признаки
объектно-ориентированного. Например,
уже в
Windows 3+ можно
поставить в соответствие кон­кретному
документу приложение для его обработки.
Тогда же поя­вился метод объектного
связывания и встраивания
(OLE),
позволя­ющий щелчком на изображении
объекта неявно запустить прило­жение,
которое его обрабатывает, а после
окончания обработки вернуться в
предыдущее приложение.

С
OLE тесно
связан так называемый метод редактирования
доку­ментов «на месте»
(in-place). Если
в документ встроен объект, ко­торый
должен обрабатываться конкретным
приложением, то при щелчке на этом
объекте нужное приложение неявным
образом за­пускается, причем в рабочем
поле не изменяется ничего, кроме па­нелей
инструментов. Например, если в тексте,
который обрабаты­вается в редакторе
Microsoft Word,
есть таблица, созданная в редакторе
Microsoft Excel,
то при щелчке на ней произойдет замена
nанелей
инстр
ументов
Excel.
Пользователь может обрабатывать документ
совсем другим приложе­нием, даже не
подозревая об этом,

Еще один механизм,
который упростил работу и приблизил
эру объ­ектно-ориентированного
подхода, называется
«Drag
&
Drop», что в
буквальном переводе означает
«перетащить-и-оставить». Работая этим
методом, вы щелкаете кнопкой мыши (как
правило, левой) на изображении объекта,
перемещаете его по экрану при нажатой
кнопке и отпускаете кнопку, когда
указатель окажется в нужном месте
экрана. Таким образом, процедуры
копирования, перемеще­ния и удаления
стали объектно-ориентированными.

Что делал
пользователь, когда ему нужно было
удалить файлы
в
опе­рационной
системе
MS-DOS? Он
запускал процедуру удаления фай­лов,
передавая их имена в качестве параметров:

del
FILEI.TXT FILE2TXT

Это действие ничем
не напоминает реальный мир, в котором
вы просто выбрасываете ненужные

Бумаги в мусорную
корзину. На первом месте для пас стоит
объект (бумага), над которым выполня­ется
процедуры (переноса в мусорную корзину),
R операционных
оболочках, которые работают под
управлением
Windows
3.1,
такое действие уже реализовано как
объектное-ориентированное
— с по­мощью
механизма
«Draw
&
Drop».
Например, в оболочке
Norton Desktop
можно схватить мышью файл и перенести
его на изобра­жение мусорной корзины.
Этого достаточно для удаления файла.
Так работа на персональном компьютере
все больше напоминает манипуляции с
объектами в реальном мире.

Выбор
показателей и параметров для оценке ОС

Windows
95 —

объектно-ориентированная ОС

Windows
95—
полноценная
операционная система

Использование
стандарта

Plug

&

Play

Планировщик заданий — средство операционной системы Windows для автоматического выполнения одноразовых или повторяющихся задач по обслуживанию системы. На компьютере требуется выполнять периодические работы по обслуживанию системы, например, задание по дефрагментации дисков или запуск сканирования Защитником Windows.

Планировщик заданий содержит несколько мастеров для планирования заданий, служба планировщика заданий управляет исполнением заданий на компьютере в определенное время.

Содержание:

  1. Планирование заданий в Windows
  2. Открытие Планировщика заданий
  3. Настройка Планировщика заданий: просмотр и управление заданиями
  4. Планировщик заданий: какие задания выполняются на компьютере в данный момент
  5. Создание задания в Планировщике заданий
  6. Создание простой задачи в Планировщике заданий
  7. Удаление задачи из Планировщика заданий
  8. Выводы статьи
  9. Планировщик заданий Windows — создание простого задания (видео)

Планировщик заданий Windows автоматически запускает программы, службы, процессы в заранее намеченное определенное время, или при наступлении тех или иных условий. Часть задач создается самой операционной системой для поддержания функционирования или обслуживания, другие задания планирует сам пользователь, или установленные программы, которые вносят свои задачи в Планировщике.

Задача в Планировщике заданий выполняет необходимые запланированные действия без участия пользователя. Пользователь может добавить собственное пользовательское задание в Планировщике Windows, которое будет выполнено в заданное время, при выполнении определенных условий, в зависимости от выбранных настроек.

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

Инструмент Планировщик заданий позволяет гибко настроить выполнение необходимых операций по администрированию и обслуживанию системы.

В операционной системе Windows имеются два основных типа планируемых заданий:

  • Стандартное задание — повседневные автоматические задачи для выполнения задач по обслуживанию системы. Пользователь видит эти задания, а при необходимости может изменить их.
  • Скрытое задание — задания для автоматизации повседневных системных задач. Они скрыты от пользователя, и в большинстве случаев, изменять их не рекомендуется, потому что от выполнения этих задач зависит работа, обслуживание и безопасность системы.

В Планировщике Windows легко настраивается сценарии выполнения заданий:

  • Задание выполняется только, когда пользователь вошел в систему, или наоборот, независимо от того, вошел пользователь в систему или нет.
  • Задание выполняется от имени пользователя или с повышенными административными правами от имени администратора.

Задания для Windows 10 могут быть несовместимы с заданиями для более ранних версий операционной системы Windows. Поэтому их нельзя просто копировать для применения на другой системе. При создании задания можно указать на совместимость с ранними версиями Windows для применения задания на других системах.

У созданных заданий имеются разные свойства:

  • Триггеры.
  • Действия.
  • Условия.

Триггеры отвечают за время начала и завершения выполнения задания. Выполнение задания или, наоборот, завершение выполнения, начинается в определенное заданное время: во время запуска системы, при входе в систему, при простаивании компьютера и т. д.

Действия определяют характер выполнения операции запущенного задания: задание запускает программы, выводит сообщения, отправляет сообщения по электронной почте.

Условия уточняют обстоятельства, по которым задание запускается или останавливается. Различные условия применяются в конкретных ситуациях, например, задание начинает выполняться при простое компьютера более 15 минут, задание прекращает выполняться при  работе от батареи, задание запускается после выхода компьютера из режима сна и т. п.

Открытие Планировщика заданий

Запустить Планировщик заданий можно из оснастки Управление компьютером, с помощью выполнения команды из диалогового окна «Выполнить», с помощью других способов, которые подробно описаны в этой статье.

Воспользуйтесь одним из универсальных способов: в поле поиска Windows введите выражение «планировщик заданий» (без кавычек), а затем запустите средство системы.

Настройка Планировщика заданий: просмотр и управление заданиями

В главном окне Планировщика заданий, в центральной части отображаются общие сведения о системном средстве и сводка о состояние задачи. Управление Планировщиком заданий задается в окне приложения.

В левой части находится Библиотека планировщика заданий с древовидной структурой папок, по которым происходит перемещение к требуемым узлам.

Центральную часть окна занимает информация о выполняемой задаче и ее свойствах. В разделе «Состояние задачи» содержится список выполняемых, успешно выполненных, остановленных и отказавших заданий.

В правой части находится раздел «Действия» для управления заданиями: создание задач, импортирование задач и т. д.

окно планировщика заданий

Для выбора задания перейдите в нужную папку в дереве консоли (Библиотека планировщика заданий).

В окне планировщика, во вкладках отображается информация о выбранном задании: общие данные, триггеры, условия, параметры, журнал.

задачи в планировщике заданий

Для выполнения действий с выбранным заданием, в разделе «Действия» необходимо выбрать один из вариантов:

  • Выполнить — запуск выполнения задачи.
  • Завершить — завершение выполнения задания.
  • Отключить — временное отключение выполнения задачи.
  • Экспорт — сохранение задания в файл для использования на другом компьютере.
  • Свойства — просмотр и, в случае необходимости, редактирование свойств задания.
  • Удалить — полное удаление задания из Планировщика заданий.
  • Справка — открытие файла справки в формате CHM с информацией о консоли управления (MMC).

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

Для отображения скрытых заданий войдите в меню «Вид», а затем поставьте флажок напротив пункта «Отображать скрытые задачи».

Планировщик заданий: какие задания выполняются на компьютере в данный момент

Пользователь может в любой момент посмотреть все выполняемые задачи в данный период времени. Для этого, выполните следующие действия:

  1. В разделе «Действия» нажмите на «Отображать все выполняемые задачи».
  2. В открывшемся окне «Все выполняемые задачи» отобразятся выполняемые задачи.

выполняемые задачи

Создание задания в Планировщике заданий

Создать задание можно несколькими способами:

  • В Библиотеке планировщика заданий выберите нужную папку, а затем щелкните правой кнопкой мыши, выберите «Создать простую задачу…» или «Создать новую задачу…».
  • В окне открытой задачи кликните правой кнопкой мыши, выберите «Создать простую задачу…» или «Создать новую задачу…».
  • В разделе «Действия» выберите «Создать простую задачу…» или «Создать задачу…».

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

Наиболее просто создается задание в разделе «Действие». Здесь находятся следующие элементы управления:

  • «Создать простую задачу…» — создание задачи с помощью мастера.
  • «Создать задачу…» — создание задачи без помощи мастера.
  • «Импортировать задачу…» — импорт задачи из другого компьютера, сохраненной в виде файла.
  • «Отображать все выполняемые задачи» — вывод отображения всех выполняемых задач в данное время.
  • «Включить журнал всех заданий» — включение ведения журнала всех заданий, или отключение ведения журнала, после включения данного параметра.
  • «Создать папку» — создание папки для задания в Библиотеке планировщика заданий.
  • «Удалить папку» — удаление папки с заданием.
  • «Вид» — изменение внешнего вида приложения, включения или отключение отображения элементов интерфейса.
  • «Обновить» — обновление параметров на текущий момент времени.
  • «Справка» — справка о работе консоли управления (MMC).

Давайте посмотрим, как создать задание в Планировщике. Для примера, мы запланируем автоматический запуск браузера Google Chrome, через некоторое время после запуска компьютера.

  1. Откройте главное окно Планировщика заданий.
  2. В разделе «Действия» нажмите на «Создание задачу…».
  3. В окне «Создание задачи», во вкладке «Общие» дайте имя для задачи, при необходимости добавьте описание, чтобы самому было понятно, если название задачи не очевидно.

Обратите внимание на раздел «Параметры безопасности». Здесь можно выбрать пользователя, наивысшие права на выполнение задачи, сделать скрытую задачу, настроить совместимость задачи с другими версиями Windows.

общие настройки

  1. Во вкладке «Триггеры» нажмите на кнопку «Создать…».

триггеры

  1. В окне «Создание триггера» в параметре «Начать задачу» необходимо выбрать условие, при котором запустится выполнение задачи. После выполнения необходимых настроек, нажмите на кнопку «ОК».

Для запуска браузера я выбрал вариант: «При входе в систему». В «Дополнительных параметрах» можно отложить задачу на определенный промежуток времени, остановить задачу, активировать, задать срок действия. Здесь я выбрал опцию отложить задачу на 3 минуты, после запуска системы.

создание триггера

  1. В окне «Создание задачи» появится созданный триггер.

триггер

  1. Во вкладке «Действия» нажмите на кнопку «Создать…».

действия

  1. В окне «Создание действия», в опции «Действие» необходимо выбрать требуемое действие. В моем случае, это «Запуск программы». В параметре «Программа или сценарий» я ввел путь до исполняемого файла браузера.

Путь до файла приложения можно скопировать из свойств ярлыка браузера Google Chrome:

"C:Program Files (x86)GoogleChromeApplicationchrome.exe"

В поле «Добавить аргументы (необязательно)» я добавил главную страницу своего сайта: «https://vellisa.ru/».

создание действия

  1. Во вкладке «Действия» отобразится запланированное действие.

действие создано

  1. Во вкладке «Условия» выберите подходящий вариант, который определяет необходимость выполнения задания.

условия

  1. Во вкладке «Параметры» нужно выбрать подходящие опции. Если потребуется, измените настройки по умолчанию.

параметры

  1. Нажмите на кнопку «ОК» для завершения создания задачи.

После запуска компьютера, браузер Google Chrome станет автоматически запускаться через 3 минуты после загрузки системы, и, в моем случае, откроет главную страницу сайта «vellisa.ru».

Создание простой задачи в Планировщике заданий

Рассмотрим следующий вариант: создание простой задачи. Пройти по шагам нам поможет встроенный Мастер создания простой задачи. С его помощью мы создадим задачу на выключение компьютера.

  1. В разделе «Действия» нажмите «Создать простую задачу…».
  2. В окне «Создать простую задачу» введите имя задачи, а затем нажмите на кнопку «Далее». При желании, добавьте описание задачи.

создание простой задачи

  1. В окне «Триггер задачи» выберите подходящий вариант для запуска задачи, а затем перейдите к следующему этапу настройки.

триггер задачи

  1. В окне «Ежедневно» (настройка триггера) выберите подходящее время и периодичность запуска задания.

ежедневно

  1. В окне «Действие» сделайте выбор действия, нажмите на кнопку «Далее».

действие

Утилита выключения компьютера находится в папке операционной системы по пути:

C:WindowsSystem32shutdown.exe
  1. В окне «Запуск программы» (настройка действие) введите путь до исполняемого файла приложения, и если нужно добавьте аргумент. В нашем случае, необходимо ввести аргумент: «/s». Для продолжения настройки задачи нажмите на «Далее».

запуск программы

  1. В окне «Сводка» ознакомьтесь с параметрами создаваемой задачи. Если потребуется, внесите коррективы, а затем нажмите на кнопку «Готово».

сводка

Задача создана, теперь компьютер будет самостоятельно завершать работу в определенное время, заданное в Планировщике заданий.

Удаление задачи из Планировщика заданий

При необходимости, пользователь может удалить ставшую ненужной задачу.

  1. В главном окне Планировщика заданий в параметре «Активные задачи» найдите нужное задание.
  2. Выделите задачу, кликните два раза левой кнопкой мыши по заданию.
  3. В окне Планировщика откроется информация о выполняемой задаче.
  4. В разделе «Действия» нажмите на кнопку «Удалить».

удаление задачи

В окне с предупреждением согласитесь на удаление задания.

Выводы статьи

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

Планировщик заданий Windows — создание простого задания (видео)

Похожие публикации:

  • Очистка папки WinSxS: чистим правильно разными способами
  • ПИН-код Windows 10: как создать, изменить или убрать
  • Как перейти с 32 битной на 64 битную версию Windows
  • Сравнение версий Windows 10: таблица
  • Установка Windows XP с флешки

Введение

Реализация одной из ответственных задач моделирования в очередной раз привела к сложностям с операционной системой. Попытка решить задачу «под Windows», т.е. просто запустить программу, не применяя специальных средств, почти удалась, однако время от времени возникали недопустимые задержки. Эти, возникавшие случайно и редко (раз в несколько минут) задержки никак не удавалось убрать. Например, последовательное снятие всех «лишних» процессов Windows улучшало ситуацию, но, в конце концов, приводило к отказу самой ОС. Положение затрудняло и то, что проведение сравнительно долгого сеанса моделирования не позволяло на все 20-30 минут сеанса установить основному работающему потоку приоритет «реального времени», так как при этом нормальная работа компьютера также нарушалась.

Обидно было менять ОС и дорабатывать свое ПО, когда результат уже был почти достигнут и требовалось всего лишь изначально не предусмотренное в Windows планирование, а именно: заданный поток в течение определенного периода не должен прерываться по истечению выделенного кванта времени, и на время его работы потоки с более низким приоритетом вообще не должны получать управление. Но при этом потоки с изначально более высоким приоритетом должны выполняться как всегда. Поскольку такие высоко приоритетные потоки обычно не занимают весь свой квант времени, время отклика для нужного потока в целом уменьшается и зависит от быстродействия компьютера.

Встал вопрос: можно ли настроить Windows на такой режим работы и как это сделать?

Планирование потоков

Как известно, переключение на другой поток в Windows происходит в трех случаях:

  • истек выделенный квант времени работы и есть потоки с таким же приоритетом;

  • поток добровольно уступает время работы (например, начинает ждать события);

  • появился готовый к работе поток с более высоким приоритетом. Он немедленно (на самом деле в момент ближайшего прерывания) получает управление.

Кроме этого, в составе планировщика Windows имеется так называемый диспетчер баланса, который поднимает приоритет до значения 15 у давно ждущих выполнения потоков. Поскольку значения приоритетов класса «реального времени» начинаются с 16, то потоки «реального времени» диспетчер баланса прервать не может, а вот остальные потоки рано или поздно уступят квант потокам с более низким приоритетом. Скорее всего, это и является источником редких непредсказуемых задержек – иногда целый квант выполняется какой-то низкоприоритетный поток.

Проведем несложный эксперимент. Запустим одновременно две копии простейшей программы, которые просто выводят на экран постоянно увеличивающееся на единицу число. Чтобы не влияла многоядерность, назначим этим задачам одно и то же ядро процессора или вообще запустим компьютер в одноядерном режиме. Две программы, как и положено, работают «одновременно» (т.е. попеременно) и примерно с одинаковой скоростью. Теперь, используя диспетчер процессов, установим одной задаче приоритет «реального времени». Эта задача продолжает работать, а вторая задача останавливается. Все ожидаемо. Однако иногда и во второй задаче выдаваемое число увеличивается!

Объясните (как говорят в Одессе, «с указочкой»), почему задача с низким приоритетом вообще получает управление, когда по условиям эксперимента есть непрерывно работающая программа с заведомо очень большим приоритетом? Ответ на этот вопрос приведен в конце статьи и, честно говоря, он имеет мало отношения к теме.

Подобные эксперименты сеют сомнения: а все ли рассказали Руссинович и Соломон в своей книге [1] или, может быть, автор статьи просто что-то не так воспринял? Возникает еще один стимул изучить, а как работает Windows «на самом деле»? Документация документацией, но, как говорится, «это все слова – покажите код».

С другой стороны, тот же Руссинович сообщает, что Windows создавали 5000 программистов. Вряд ли одному человеку под силу разобраться во всех тонкостях такой большой и сложной системы. К счастью, разобраться требуется только в одной из многочисленных сторон ОС. А это вполне возможно и одному человеку и за сравнительно небольшое время.

Постановка задачи

Конкретизируем задачу. Требуется проанализировать код ядра Windows в части переключения с одного потока на другой. Нужно убедиться, что никаких других случаев переключения, кроме трех перечисленных, в ядре нет. Используя результаты анализа и знание конкретного кода, переключающего потоки, требуется организовать работу планировщика так, чтобы заданный поток в течение 20-30 минут не прерывался потоками с более низким приоритетом (из-за работы диспетчера баланса), но при этом не обладал приоритетом «реального времени» и поэтому не мешал различным высокоприоритетным служебным потокам и сервисам.

Получение кода для анализа

К сожалению, получить текст кода ядра для анализа не так-то просто. Т.е. ядро ntoskrnl.exe невозможно просто загрузить в память с помощью какого-нибудь ntsd или windbg. Конечно, есть и специальные средства, и отладочные версии, и виртуальные машины, но в данном случае хотелось бы получить просто ассемблерный код как текст, который можно даже хотя бы частично распечатать и спокойно анализировать «за столом». Для этой цели проще создать небольшую программу (я назвал ее sd.exe) самому. Поскольку в используемых мною средствах есть встроенный отладчик, легко написать небольшую программу, просто загружающую файл ntoskrnl в память и затем сдвигающую на нужную величину каждую секцию, перечисленную в таблице заголовка exe-файла. Выполнив эти действия, программа останавливается в контрольной точке (т.е. на команде INT 3). В результате в памяти получается правильно «развернутый» образ ядра из ntoskrnl, который теперь можно вывести на экран или в файл командами «U» и «D» встроенного интерактивного отладчика. Сложность такого дизассемблирования в том, что команды и данные идут вперемежку, и если весь файл вывести как команды, данные выведутся как набор бессмысленных команд, часто портящих начало участков настоящих команд. Приходится предварительно все просматривать на экране как данные и на глаз определять очередные границы команд и данных. Результаты просмотра оформляются в виде текста как последовательность команд «U» и «D» для будущего получения «распечатки»:

…
U EAX+17EC2B EAX+17FA09
D EAX+17FA00 EAX+17FA3F
U EAX+17FA4A EAX+180DF7
D EAX+180DF0 EAX+180EFF
…

Здесь все адреса указаны относительно регистра EAX, в который в программе sd.exe записывается адрес загрузки файла ntoskrnl в памяти. Иногда удобнее вместо команды «D» использовать также имеющуюся в данном отладчике команду «DD», выводящую данные двойными словами, т.е. адресами. Например, вот адреса рассылки по прерываниям INT 00, INT 01, INT 02,…:

DD EAX+1EE0FC
5EE0FC  00407522 00088E00-004076A1 00088E00
5EE10C  00407794 00088E00-00407AB5 0008EE00
5EE11C  00407C38 0008EE00-00407D9D 00088E00
5EE12C  00407F1E 00088E00-00408597 00088E00
5EE13C  004088A5 00088E00-0040899C 00088E00
5EE14C  00408ABA 00088E00-00408BF7 00088E00
5EE15C  00408E54 00088E00-00409150 00088E00
5EE16C  00409899 00088E00-00409B16 00088E00
5EE17C  00409C34 00088E00-00409D6E 00088E00
5EE18C  00409B16 00088E00-00409B16 00088E00
…

Кстати, найденный адрес 409150 исключения INT 0D «нарушение общей защиты» еще пригодится далее.

Теперь если отладчик выполнит последовательность команд «U» и «D», получается текст вот такого, уже более правильного вида:

…
57F9F7 90                            NOP
57F9F8 8B65E8                        MOV    ESP,[EBP]+FFFFFFE8
57F9FB 8B7DCC                        MOV    EDI,[EBP]+FFFFFFCC
57F9FE 834DFCFF                      OR     D PTR [EBP]+FFFFFFFC,FFFFFFFF
57FA02 8BC7                          MOV    EAX,EDI
57FA04 E825C4E8FF                    CALL   40BE2E
57FA09 C20800                        RET    0008

57FA00  FC FF 8B C7 E8 25 C4 E8-FF C2 08 00 0A 20 53 75                  .. Su
57FA10  62 6B 65 79 73 20 6F 70-65 6E 20 69 6E 73 69 64       bkeys open insid
57FA20  65 20 74 68 65 20 68 69-76 65 20 28 25 70 29 20       e the hive (%p) 
57FA30  28 25 2E 2A 53 29 20 3A-0A 0A 00 CC CC CC CC CC       (%.*S) :...

57FA4A 6A34                          PUSH   00000034
57FA4C 6890844500                    PUSH   00458490
57FA51 E89DC3E8FF                    CALL   40BDF3
57FA56 33DB                          XOR    EBX,EBX
57FA58 66895DCC                      MOV    [EBP]+FFFFFFCC,BX
57FA5C 33C0                          XOR    EAX,EAX
…

Таким образом, команды отделяются от данных. Всю последовательность команд для отладчика я записал в файл ud.txt и одной командой:

sd.exe ntoskrnl.exe <ud.txt >ntos.txt

получил первый вариант кода ядра в текстовом файле ntos.txt. Этот вариант еще достаточно «слепой». Однако теперь уже несложно создать еще одну небольшую программу, которая обработает полученный результат, добавляя в текст названия импортируемых процедур, используя таблицу импорта исходного exe-файла, а также расставит метки по тексту, используя адреса таблицы экспортируемых функций. Кроме этого, программа вставляет всякие удобные мелочи вроде пустой строки после каждой команды RET, чтобы легче читать анализируемые участки и т.д.

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

…
KeReleaseMutant:
402B4C 8BFF                 MOV    EDI,EDI
402B4E 55                   PUSH   EBP
402B4F 8BEC                 MOV    EBP,ESP
402B51 53                   PUSH   EBX
402B52 56                   PUSH   ESI
402B53 57                   PUSH   EDI
402B54 33C9                 XOR    ECX,ECX
402B56 FF1588104000         CALL D PTR [00401088]; KeAcquireQueuedSpinLockRaiseToSynch
402B5C 8B7508               MOV    ESI,[EBP]+00000008
402B5F 8AD8                 MOV    BL,AL
402B61 8B4604               MOV    EAX,[ESI]+00000004
402B64 894508               MOV    [EBP]+00000008,EAX
402B67 64A124010000         FS:    MOV    EAX,[00000124] ;ТЕКУЩИЙ ПОТОК
402B6D 807D1000             CMP    B PTR [EBP]+00000010,00
402B71 8BF8                 MOV    EDI,EAX
402B73 0F85AFB30100         JNE   41DF28
…

Самое главное, что теперь в этом большом (26 Мбайт) текстовом файле легко искать нужный контекст, например, переход на заданный адрес. А значит, можно приступать собственно к анализу кода ядра.

Анализ кода

По условиям задачи анализировать потребовалось ядро Windows-XP SP3 сборки 0421 от 4 июля 2013 года. При этом в очень большом тексте (примерно 570 000 ассемблерных строк) нужно было по возможности быстро найти элементы планировщика, отвечающие за переключение потоков.

С чего начать? Очевидно с поиска «сердца» ОС – т.е. с процедуры, вызываемой при каждом аппаратном срабатывании сигнала встроенных часов. Это просто, ведь есть экспортируемое имя KeUpdateSystemTime и его адрес 40B558 (далее комментарии в тексте частью расставлены программой, частью дописаны вручную):

;=========== ВЫПОЛНЕНИЕ ОДНОГО ТАКТА ОПЕРАЦИОННОЙ СИСТЕМЫ =============
;----- НА ВХОДЕ В ЕАХ ЧИСЛО ТИКОВ СИСТЕМНЫХ ЧАСОВ С ПРОШЛОГО ВЫЗОВА ---

KeUpdateSystemTime:

40B558 B90000DFFF           MOV    ECX,FFDF0000

;----- ЗАПОМИНАЕМ ЧИСЛО ТЕКУЩИХ ТИКОВ ЧАСОВ ----

40B55D 8B7908               MOV    EDI,[ECX]+00000008
40B560 8B710C               MOV    ESI,[ECX]+0000000C
40B563 03F8                 ADD    EDI,EAX
40B565 83D600               ADC    ESI,00000000
40B568 897110               MOV    [ECX]+00000010,ESI
40B56B 897908               MOV    [ECX]+00000008,EDI
40B56E 89710C               MOV    [ECX]+0000000C,ESI

;----- УМЕНЬШАЕМ ВРЕМЯ ТЕКУЩЕГО КВАНТА ----

40B571 290514304800         SUB    [00483014],EAX
40B577 A100304800           MOV    EAX,[00483000] ;СИСТЕМНЫЙ ТИК
40B57C 8BD8                 MOV    EBX,EAX
40B57E 0F8F84000000         JJG    40B608
…

Далее идет обновление числа «тиков» и проверки таймеров, а затем самый важный для анализа фрагмент:

…
;----- ЕСЛИ КВАНТ ИСТЕК, ВЫПОЛНЯЕМ РАБОТЫ НА ГРАНИЦЕ КВАНТА ----
40B682 833D1430480000       CMP    D PTR [00483014],00000000
40B689 7F1F                 JG     40B6AA

;----- ОПЯТЬ УСТАНОВИЛИ КВАНТ ----
40B68B A10C304800           MOV    EAX,[0048300C]
40B690 010514304800         ADD    [00483014],EAX

40B696 FF3424               PUSH   D PTR [ESP]
40B699 E846000000           CALL   40B6E4 ;KeUpdateRunTime
40B69E FA                   CLI
40B69F FF1594104000         CALL   D PTR [00401094]; HalEndSystem Interrupt
40B6A5 E983BBFFFF           JMP    40722D ;Kei386EoiHelper

;----- КВАНТ НЕ ИСТЕК - СРАЗУ ВЫХОДИМ ----
40B6AA 64FF05C4050000       FS:    INC    D PTR [000005C4]
40B6B1 FA                   CLI
40B6B2 FF1594104000         CALL   D PTR [00401094];    HalEndSystem Interrupt
40B6B8 E970BBFFFF           JMP    40722D ;Kei386EoiHelper
…

Т.е. при каждом окончании времени кванта запускается подпрограмма с вполне соответствующим случаю названием KeUpdateRunTime.

Она расположена по тексту рядом:

KeUpdateRunTime:
40B6E4 64A11C000000         FS:    MOV    EAX,[0000001C]
40B6EA 53                   PUSH   EBX
40B6EB FF80C4050000         INC    D PTR [EAX]+000005C4

;---- ДОСТАЕМ ТЕКУЩЕ ВЫПОЛНЯЕМЫЙ ПОТОК И ПРОЦЕСС ----

40B6F1 8B9824010000         MOV    EBX,[EAX]+00000124
40B6F7 8B4B44               MOV    ECX,[EBX]+00000044
…

Откуда следует, что это достаются именно текущий поток и процесс?

Это легко выясняется, например, из процедуры KeGetCurrentThread:

KeGetCurrentThread:
404622 64A124010000         FS:    MOV    EAX,[00000124] ;ТЕКУЩИЙ ПОТОК
404628 C3                   RET

И из процедуры IoGetCurrentProcess:

IoGetCurrentProcess:
40ED86 64A124010000         FS:    MOV    EAX,[00000124] ;ТЕКУЩИЙ ПОТОК
40ED8C 8B4044               MOV    EAX,[EAX]+00000044
40ED8F C3                   RET

Самое интересное место расположено в конце KeUpdateRunTime:

…
40B81A 806B6F03             SUB    B PTR [EBX]+0000006F,03
40B81E 7F19                 JG     40B839
40B820 3B982C010000         CMP    EBX,[EAX]+0000012C
40B826 7411                 JZ     40B839
40B828 89A0AC090000         MOV    [EAX]+000009AC,ESP
40B82E B902000000           MOV    ECX,00000002
40B833 FF150C114000         CALL   D PTR [0040110C]; HalRequestSoftware Interrupt
40B839 5B                   POP    EBX
40B83A C20400               RET    0004

Здесь из некоторого поля внутренней структуры текущего потока со смещением 6F вычитается 3 и, если этот счетчик становится не положительным, в некоторую переменную с относительным адресом 9AC заносится зачем-то значение ESP. А где используется такая переменная? Оказывается, контекстный поиск смещения 9AC находит одно единственное место внутри KiDispatchInterrupt:

…
405891 FB                   STI
405892 83BBAC09000000       CMP    D PTR [EBX]+000009AC,00000000
405899 0F8581000000         JJNE   405920
40589F 83BB2801000000       CMP    D PTR [EBX]+00000128,00000000
4058A6 746F                 JZ     405917
4058A8 FA                   CLI
…
4058BF B91C000000           MOV    ECX,0000001C
4058C4 FF152C104000         CALL   D PTR [0040102C];KfRaiseIrql
4058CA FB                   STI
4058CB 8B8328010000         MOV    EAX,[EBX]+00000128

4058D1 83EC0C               SUB    ESP,0000000C
…
4058DF 8BF0                 MOV    ESI,EAX
4058E1 8BBB24010000         MOV    EDI,[EBX]+00000124
4058E7 C7832801000000000000 MOV    D PTR [EBX]+00000128,00000000
4058F1 89B324010000         MOV    [EBX]+00000124,ESI
4058F7 8BCF                 MOV    ECX,EDI
4058F9 C6475001             MOV    B PTR [EDI]+00000050,01
4058FD E865FDFFFF           CALL   405667
405902 B101                 MOV    CL,01
405904 E839000000           CALL   405942
…
405917 C3                   RET
…
405920 C783AC09000000000000 MOV    D PTR [EBX]+000009AC,00000000
40592A E890C10000           CALL   411ABF
40592F 0BC0                 OR     EAX,EAX
405931 759E                 JNZ    4058D1
405933 C3                   RET

Если значение переменной 9AC не равно нулю, оно сбрасывается, затем идет обращение к некоторой процедуре по адресу 411ABF. И если процедура возвращает ненулевой EAX, то управление попадает на адрес 4058D1. А здесь это значение (командой по адресу 4058F1) пишется как новый текущий поток. Вот нужное место и найдено!

Теперь понятна вся цепочка действий ядра: на каждый «тик» встроенных часов запускается KeUpdateSystemTime, где текущий квант уменьшается на число прошедших «тиков». Если квант истек, запускается KeUpdateRunTime, которая уменьшает внутренний счетчик в структуре текущего потока. Как только этот счетчик истекает, данное событие отмечается в переменной с относительным адресом 9AC. При ближайшем прерывании запускается KiDispatchInterrupt, которая проверяет переменную 9AC. Если переменная не нулевая (именно для этого в нее занесли ESP) – значит время данного потока исчерпано.

С помощью подпрограммы по адресу 411ABF ОС ищет новый поток для работы. Если конкурента текущему потоку не находится, он продолжает выполнение. Иначе текущий поток переводится в режим ожидания с помощью процедуры по адресу 405667, и запускается (т.е. становится текущим) другой поток.

Интересно, что внутри процедуры с адресом 411ABF проверяется, равно ли нулю поле 69 структуры текущего потока. Если нет – новый поток не ищется. Это поле описано в документации как DisableQuantum. Т.е. квант работы можно сделать бесконечным!

Увы, установить это поле из режима пользователя нельзя. Сама ОС может установить любое значение этого поля с помощью внутренней процедуры по адресу 43CA4B. Однако когда она использует эту подпрограмму, всегда данное поле устанавливается в ноль. Жаль, было бы удобно с помощью какого-нибудь недокументированного сервиса задать себе таким способом «бесконечный» квант работы.

Обратите внимание, что не только переменная 9AC может вызвать смену потока. Точно так же поток меняется, если значение поля с относительным адресом 128 не нулевое. По адресу 4058D1 начинается общая для двух этих случаев часть действий ОС по смене потока. Не вызывает сомнения, что проверка переменной со смещением 128 — это как раз случай появления потока с более высоким приоритетом.

А есть ли еще места смены текущего потока? Да, есть, и они по тексту рядом.

…
405830 648B1D1C000000       FS:    MOV    EBX,[0000001C]
405837 8BF1                 MOV    ESI,ECX
405839 8BBB24010000         MOV    EDI,[EBX]+00000124
40583F 89B324010000         MOV    [EBX]+00000124,ESI
405845 8A4F58               MOV    CL,[EDI]+00000058
405848 E8F5000000           CALL   405942
…

Это подпрограмма вызывается, например, внутри KeWaitForMultipleObjects. Очевидно, что это случай «добровольной» смены потока при ожиданиях, задержках, окончании задачи и т.п.

Наконец, еще одно место изменения поля со смещением 124 находится контекстным поиском чуть выше:

…
40574A 64833D2801000000     FS:    CMP    D PTR [00000128],00000000
405752 7544                 JNZ    405798
…
405767 FF2530104000         JMP    D PTR [00401030];KfLowerIrql

40576D 64833D9409000000     FS:    CMP    D PTR [00000994],00000000
405775 75DD                 JNZ    405754
405777 51                   PUSH   ECX
405778 64A120000000         FS:    MOV    EAX,[00000020]
40577E 8D8818040000         LEA    ECX,[EAX]+00000418
405784 E81B5D0000           CALL   40B4A4 ;ОСВОБОДИТЬ ОЧЕРЕДЬ
405789 B102                 MOV    CL,02
40578B FF150C114000         CALL   D PTR [0040110C]; HalRequestSoftware Interrupt
405791 59                   POP    ECX
405792 FF2530104000         JMP    D PTR [00401030];KfLowerIrql

405798 80F902               CMP    CL,02
40579B 7DD0                 JNL    40576D
…
4057AF 648B1D1C000000       FS:    MOV    EBX,[0000001C]
4057B6 8BB328010000         MOV    ESI,[EBX]+00000128
4057BC 8BBB24010000         MOV    EDI,[EBX]+00000124
4057C2 C7832801000000000000 MOV    D PTR [EBX]+00000128,00000000
4057CC 89B324010000         MOV    [EBX]+00000124,ESI
4057D2 884F58               MOV    [EDI]+00000058,CL
4057D5 8BCF                 MOV    ECX,EDI
4057D7 C6475001             MOV    B PTR [EDI]+00000050,01
4057DB E887FEFFFF           CALL   405667
4057E0 8A4F58               MOV    CL,[EDI]+00000058
4057E3 E85A010000           CALL   405942
…

Здесь уже не проверяется переменная 9AC, но опять проверяется наличие потока с более высоким приоритетом. Очевидно, что это обработка прерывания, случившегося внутри самой ОС, где квант не может истечь по определению, но на появление готового потока с более высоким приоритетом нужно реагировать немедленно.

И это весь анализ по части смены потока. Контекстным поиском больше не найдено мест, где бы менялся текущий поток (по смещению 124). А значит, анализировать остальные сотни тысяч строк ассемблерного кода уже нет никакой необходимости. ОС именно так как описано в документации меняет текущий поток или по исчерпанию заданного числа квантов (что определяется счетчиком в поле 6F структуры текущего потока) или при появлении более высокоприоритетного или если поток сам уступает время выполнения. Других «секретных» способов не обнаружено. Для решения поставленной задачи осталось лишь понять работу диспетчера баланса. Кстати, где он?

Диспетчер баланса использует понятие «старения» ждущих потоков. Значит, он должен достать текущий «тик» (переменная по адресу [483000], меняющаяся только внутри KeUpdateSystemTime), затем отнять из него некоторую константу и полученное значение сравнивать со временем перевода данного потока в режим ожидания. Это время должно храниться где-то в структуре каждого ждущего потока. Несложно найти в тексте все вычитания из системного «тика». Например, вот место доставания текущего времени и вычитание из него константы 300:

…
40F47B A100304800           MOV    EAX,[00483000] ;СИСТЕМНЫЙ ТИК
40F480 53                   PUSH   EBX
40F481 56                   PUSH   ESI
40F482 33F6                 XOR    ESI,ESI
40F484 46                   INC    ESI
40F485 8BDE                 MOV    EBX,ESI
40F487 894DF8               MOV    [EBP]+FFFFFFF8,ECX
40F48A D3E3                 SHL    EBX,CL
40F48C 2D2C010000           SUB    EAX,0000012C ; ВЫЧИТАЕМ 300
…

Если это и есть диспетчер баланса, тогда вот в нем сама проверка степени «старения» потока по времени его ожидания в поле со смещением 68:

…
410345 8B45EC               MOV    EAX,[EBP]+FFFFFFEC
410348 8D4EA0               LEA    ECX,[ESI]+FFFFFFA0
41034B 3B4168               CMP    EAX,[ECX]+00000068 ;НАЧАЛЬНЫЙ ТИК
41034E 0F83E5540300         JJAE   445839
410354 8B45F8               MOV    EAX,[EBP]+FFFFFFF8
410357 8B36                 MOV    ESI,[ESI]
…

А вот и нашлось поднимание текущего приоритета до 15, а также указанное в документации удвоение времени работы в кванте в этом случае:

…
445856 B00F                 MOV    AL,0F
445858 2A4133               SUB    AL,[ECX]+00000033 ;ПРИОРИТЕТ ПОТОКА
44585B C6416D10             MOV    B PTR [ECX]+0000006D,10
44585F 00416E               ADD    [ECX]+0000006E,AL
445862 8B4144               MOV    EAX,[ECX]+00000044
445865 C641330F             MOV    B PTR [ECX]+00000033,0F ;НОВЫЙ ПРИОРИТЕТ ПОТОКА
445869 8A4063               MOV    AL,[EAX]+00000063
44586C D0E0                 SHL    AL,1
44586E 88416F               MOV    [ECX]+0000006F,AL ; УДВОЕНИЕ ВРЕМЕНИ КВАНТА
445871 E8F1FDFBFF           CALL   405667
…

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

Изменение поведения планировщика

Теперь мы вооружены знаниями о том, как на уровне кодов происходит смена потока в Windows. Но как заставить планировщик работать в соответствии с поставленной задачей? Т.е., во-первых, сделать квант «бесконечным» на время работы заданного потока, а во-вторых, не допустить, чтобы диспетчер баланса поднял приоритет давно ждущих потоков выше приоритета заданного потока.

Для этого требуется внести исправление в само ядро. Это не так уж и сложно. Конечно, потребуется позаботиться о пересчете контрольной суммы с помощью процедуры CheckSumMappedFile и тому подобных мелочах, но это не является серьезным препятствием. Самое главное – организовать удобный интерфейс задачи пользователя с ядром. Напоминаем, что это делается для единственного компьютера.

Была выбрана схема, при которой запущенный поток сам периодически сообщает ядру о своей «избранности». При получении этого сообщения ядро продлевает квант выполнения и ограничивает подъем приоритетов диспетчером баланса не выше заданного. Как только (минут через 20-30) поток завершается, он перестает давать сообщения ядру. Поэтому ОС опять начинает выполнять фрагмент кода по исчерпанию кванта (для других потоков). В этом месте будет срабатывать возврат диспетчера баланса в нормальный режим работы. Таким образом, после завершения нужного потока ядро автоматически возвращается в обычный режим работы.

Сначала нужно найти место для размещения дополнительных команд. Таких мест много, например, команды можно написать вместо вот этого длинного диагностического текста, который вряд ли когда потребуется:

555390  E8 CE DC EA FF C9 C2 04-00 90 2A 2A 2A 2A 2A 2A        ..Р******
5553A0  2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
5553B0  2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
5553C0  2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
5553D0  2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
5553E0  2A 2A 2A 2A 2A 2A 2A 2A-2A 0A 2A 0A 2A 20 54 68 *********.*.* Th
5553F0  69 73 20 69 73 20 74 68-65 20 73 74 72 69 6E 67 is is the string
555400  20 79 6F 75 20 61 64 64-20 74 6F 20 79 6F 75 72  you add to your
555410  20 63 68 65 63 6B 69 6E-20 64 65 73 63 72 69 70  checkin descrip
555420  74 69 6F 6E 0A 2A 20 44-72 69 76 65 72 20 56 65 tion.* Driver Ve
555430  72 69 66 69 65 72 3A 20-45 6E 61 62 6C 65 64 20 rifier: Enabled 
555440  66 6F 72 20 25 5A 20 6F-6E 20 42 75 69 6C 64 20 for %Z on Build 
555450  25 6C 64 20 25 77 5A 0A-2A 0A 2A 2A 2A 2A 2A 2A %ld %wZ.*.******
555460  2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
555470  2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
555480  2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
555490  2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
5554A0  2A 2A 2A 2A 2A 2A 2A 2A-2A 0A 00 CC CC CC CC CC *********..

Передача сообщения ядру происходит с помощью выполнения привилегированной команды, на которую сработает исключение INT 0D «нарушение общей защиты». При этом предварительно в одном из регистров пишется специальное значение, которое и позволит ядру отличить этот случай от всех остальных. Кстати, само ядро тоже пользуется похожим приемом, например, в интерфейсе запроса времени INT 2A в регистре EBP можно записать специальные значения F0F0F0F0 или F0F0F0F1, которые заставят ядро реагировать на INT 2A по-разному.

Для начала команды обработчика исключения INT 0D в ядре по адресу 409150 можно немного «уплотнить» и добавить вызов новой подпрограммы (размещенной по адресу 5553A0 на месте текста), не двигая остальной код обработчика:

;---- ИСХОДНЫЙ ОБРАБОТЧИК ИСКЛЮЧЕНИЯ «ОБЩЕЕ НАРУШЕНИЕ ЗАЩИТЫ» ----

409150 F744240C00000200              TEST   D PTR [ESP]+0C,00020000
409158 0F843A010000                  JJE    409298
40915E 83EC64                        SUB    ESP,0064
409161 66C74424660000                MOV    W PTR [ESP]+66,0000
409168 895C245C                      MOV    [ESP]+005C,EBX
40916C 89442444                      MOV    [ESP]+0044,EAX
…
;---- ДОРАБОТАННЫЙ ОБРАБОТЧИК ИСКЛЮЧЕНИЯ «ОБЩЕЕ НАРУШЕНИЕ ЗАЩИТЫ» ----

409150 E84BC21400                    CALL   5553A0 ; ВСТАВЛЕННЫЙ ВЫЗОВ ОБРАБОТКИ
409155 F644240E02                    TEST   B PTR [ESP]+000E,02
40915A 0F8438010000                  JJE    409298
409160 83EC64                        SUB    ESP,0064
409163 895C245C                      MOV    [ESP]+005C,EBX
409167 89442444                      MOV    [ESP]+0044,EAX
40916B 33C0                          XOR    EAX,EAX
40916D 6689442466                    MOV    [ESP]+0066,AX
…

Как видите, при необходимости даже оптимизированный код можно «ужать» и вставить дополнительные команды.

А на место диагностического текста помещаются основные команды исправления ядра:

;---- ПРОВЕРКА СИГНАТУРЫ ----
5553A0 81FE44445555                  CMP    ESI,55554444
5553A6 7401                          JZ     5553A9
5553A8 C3                            RET

;---- ОБРАБОТКА СООБЩЕНИЯ ---
5553A9 1E                            PUSH   DS
5553AA 0FA0                          PUSH   FS
5553AC 66BB3000                      MOV    BX,0030
5553B0 66B82300                      MOV    AX,0023
5553B4 8EE3                          MOV    FS,BX
5553B6 8ED8                          MOV    DS,AX

;---- ПРОДЛЕВАЕМ КВАНТ РАБОТЫ ТЕКУЩЕГО ПОТОКА ----
5553B8 64A124010000                  FS:    MOV    EAX,[00000124]
5553BE C6406F7F                      MOV    B PTR [EAX]+006F,7F

;---- ЗАДАЕМ МАКСИМАЛЬНЫЙ ПРИОРИТЕТ ДЛЯ ДИСПЕТЧЕРА БАЛАНСА ----
5553C2 8A4833                        MOV    CL,[EAX]+0033
5553C5 E800000000                    CALL   5553CA
5553CA 5B                            POP    EBX
5553CB 884B3A                        MOV    [EBX]+003A,CL
5553CE 0FA1                          POP    FS
5553D0 1F                            POP    DS

;---- ВОЗВРАЩАЕМСЯ ИЗ ИСКЛЮЧЕНИЯ В ЗАДАЧУ ----
5553D1 FF442408                      INC    D PTR [ESP]+0008
5553D5 FF442408                      INC    D PTR [ESP]+0008
5553D9 83C408                        ADD    ESP,0008
5553DC CF                            IRET

Дополнительный обработчик исключения проверяет сигнатуру ESI=55554444 и выполняет следующие действия:

— устанавливает максимальное значение счетчика 127 для текущего потока;

— достает приоритет текущего потока и вставляет его как константу прямо внутрь команды, через которую проходит управление в диспетчере баланса. Чтобы найти относительный адрес исправляемой команды, выполняется фиктивный вызов процедуры;

— пропускает команду, которая вызвала это исключение, выбрасывает из стека адрес возврата и код ошибки и возвращается прямо в задачу пользователя.

По сути, Windows вообще не «чувствует» такое исключение, поскольку управление сразу же возвращается в задачу, минуя обычные пути обработки исключений. В программе достаточно хотя бы раз в 2-3 секунды давать исключение с таким значением в ESI и тогда внутренний счетчик потока по адресу 6F никогда не достигнет нуля. А значит, переменная 9AC продолжает оставаться нулевой и Windows не ищет замену текущему потоку.

Остается поправить диспетчер баланса. В него добавляются команды, проверяющие приоритет ждущего потока. Если приоритет ниже, диспетчер действует так, как будто поток еще не «старый»:

…
410348 8D4EA0                        LEA    ECX,[ESI]+FFA0
41034B 3B4168                        CMP    EAX,[ECX]+0068
41034E E998501400                    JMP    5553FB
410353 90                            NOP
…
;---- УЧЕТ НУЖНОГО ПРИОРИТЕТА В ДИСПЕТЧЕРЕ БАЛАНСА ----
5553FB 0F8653AFEBFF                  JJB    410354
555401 80793310                      CMP    B PTR [ECX]+0033,10
555405 0F8549AFEBFF                  JJBE   410354
55540B E92904EFFF                    JMP    445839

Первоначально приоритет сравнивается с константой 16, которой у проверяемых потоков не может быть, и поэтому проверка никак не влияет на обычную работу диспетчера. Но когда начинают приходить сообщения от «избранного» потока, константа 16 прямо в команде проверки заменяется значением приоритета заданного потока. Теперь всем более низкоприоритетным потокам диспетчер уже не пытается поставить приоритет 15.

Требуется лишь вернуть константу 16 на место после того, как заданный поток закончился. В этом случае ОС опять начинает выполнять поиск потоков по исчерпанию кванта, в это место и можно добавить команды восстановления:

…
40592A E890C10000                    CALL   411ABF
40592F E9986D0400                    JMP    5553DE
…
;---- ВОССТАНАВЛИВАЕМ ОБЫЧНЫЙ РЕЖИМ ДИСПЕТЧЕРА БАЛАНСА ----
5553DE 50                            PUSH   EAX
5553DF E800000000                    CALL   5553E4
5553E4 58                            POP    EAX
5553E5 C6402010                      MOV    B PTR [EAX]+0020,10
5553E9 58                            POP    EAX
5553EA 0BC0                          OR     EAX,EAX
5553EC 0F85EF04EBFF                  JJNE   4058D1
5553F2 C3                            RET

Все перечисленные вставки кодов записаны непрерывно на месте диагностического текста и разделены здесь лишь для более наглядного пояснения их работы.

Доработка прикладного ПО

Анализ и исправление ядра ОС занял примерно неделю, зато все прикладное ПО осталось без изменения, за исключением добавления в одном месте в главный цикл основного модуля подпрограммы выдачи сообщения ядру.

На языке PL/1 подпрограмма выдачи сообщения ядру выглядит так:

Продление_Кванта:proc;
dcl ?ESI bit(32);
?ESI=’55554444’b4; // в регистр ESI помещаем сигнатуру
unspec('0F08'b4);  // код любой «запрещенной» команды из 2-х байт
end Продление_Кванта;

Достаточно хотя бы раз в 2-3 секунды (т.е. пока не истечет внутренний счетчик, нужно опять успеть присвоить ему максимальное значение) обращаться из задачи пользователя к этой процедуре, как данный поток будет работать, не прерываясь на целые кванты для менее приоритетных потоков.

Заключение

Может показаться, что затрачено непропорционально много сил и времени лишь на то, чтобы заставить Windows работать неправильно. Но это не так. Поведение ОС не должно быть незыблемой данностью, указанной свыше. Есть большое число случаев, когда программа предназначена не для массовой работы на любых компьютерах (разумеется, тогда исправление ОС невозможно), а на конкретной машине и конкретной версии ОС.

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

Однако данный пример показывает, что даже основные архитектурные особенности самой распространенной в мире ОС могут быть перенастроены для конкретного случая, превращая ее практически в систему реального времени. И при этом не требуется доскональное изучение всей ОС (да это и нереально), достаточно, исходя из логики и общих соображений, исследовать несколько подходящих мест. Для этого понадобилась лишь пара простых программ и текстовый редактор с контекстным поиском. Подобной технологией можно создать свою версию практически для любого случая без радикальной переделки всей системы.

И с юридической точки зрения это допустимо. Например, статья 6 Директивы 2009/24/EC или статья 25 Закона РФ об авторском праве [2] разрешают адаптацию программ для функционирования на технических средствах покупателя программы.

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

P.S. А тогда почему пример с двумя задачами так странно работал, раз в ядре не нашлось недокументированного планирования? Все просто. Сам пример был в данном случае некорректен. Ведь каждая из программ выдавала значение на экран обращением к стандартному файлу консольного вывода, причем в синхронном режиме. Т.е. наступал момент, когда задача с приоритетом «реального времени» просто уступала свое время, дожидаясь окончания выдачи на экран. В этот момент планировщик запускал поток с низким приоритетом, который успевал сменить значение переменной и сам уступал из-за выдачи на экран свое время, что вызывало возобновление работы высокоприоритетной задачи. Если отменить выдачу на экран, зацикленная задача приоритета «реального времени» просто «подвесит» весь компьютер (ну, или ядро на многоядерном процессоре), о чем и предупреждает документация.

Литература

1.       М. Руссинович, Д. Соломон Внутреннее устройство Microsoft Windows, Windows Server™ 2003, Windows XP и Windows 2000 4-е издание

2.       www.internet-law.ru

Понравилась статья? Поделить с друзьями:
  • Как пользоваться touch vpn для windows 10
  • Как пользоваться total commander для windows 10
  • Как пользоваться telnet на windows 10
  • Как пользоваться telnet для windows 7
  • Как пользоваться teamviewer на windows 10