правление процессами операционной системы
С точки зрения операционной системы ядро Oracle - это обычное приложение. В его работе нет ничего мистического - это просто огромная и весьма впечатляющая программа на языке C. Для полного понимания хронометрических данных, предоставляемых ядром Oracle, необходимо поближе познакомиться с возможностями самого ядра, в свою очередь предоставляемых ему операционной системой.
В этом разделе мы уделим основное внимание поведению операционных систем, основанных на UNIX. Изложенный здесь материал достаточно адекватно описывает поведение клонов UNIX, таких как Linux, Sun Solaris, HP-UX, IBM AIX и Tru64. Но сведения из этого раздела будут интересны и тем, кто работает с MS Windows. Те же, кто работает с какой-то другой ОС, должны будут обратиться за дополнительной информацией к руководству по этой ОС.
Я считаю, что лучшее описание функционирования процесса в контексте современной ОС дал Морис Бах (Maurice Bach) в своей книге «The Design of the Unix Operating System» (Архитектура операционной системы Unix, [Bach 1986 (31)]). Рисунок 2.6 из этой книги, озаглавленный «Process States and Transitions» (Состояния процесса и переходы между ними) и воспроизведенный на рис. 7.1, будет отправной точкой моего рассказа. На этой схеме каждый узел (прямоугольник) представляет состояние, которое процесс может принимать в операционной системе. Каждое ребро (направленная линия) - это переход из одного состояния в другое. Можно воспринимать состояния как существительные, а переходы - как глаголы, которые вызывают переход процесса из одного состояния в следующее.
Большая часть процессов ядра Oracle проводит основную часть своего времени в состоянии выполнения пользователем (user running), называемом также пользовательским, или непривилегированным, режимом (user mode). Разбор SQL, сортировка строк, чтение блоков кэша буферов и преобразование типов данных - все эти операции Oracle выполняет в пользовательском режиме. Переход процесса из пользовательского режима в привилегированный (kernel mode) может быть инициирован одним из двух событий. Вам необходимо понимат
ь оба варианта такого перехода, поэтому рассмотрим их более подробно.
Когда процесс, находящийся в пользовательском режиме, совершает вызов операционной системы, он переходит в привилегированный режим. К типичным системным вызовам относятся read и select. В привилегированном режиме процесс наделяется специальными полномочиями, которые позволяют ему манипулировать низкоуровневыми аппаратными компонентами и произвольными ячейками памяти. Например, в привилегированном режиме процесс может управлять устройствами ввода/вывода, такими как сокеты и дисковые устройства [Bovet and Cesati (2001) 8].
Можно ожидать, что многие системные вызовы будут проводить в ожидании ответа от устройства очень много процессорных циклов. Например, вызов read для дисковой подсистемы сегодня обычно выполняется за время порядка нескольких миллисекунд. Многие же нынешние процессоры способны выполнить миллионы инструкций за то время, пока будет выполняться единственная операция физического дискового ввода/вывода. Так что за время одного вызова чтения можно выполнить порядка миллиона инструкций процессора. Естественно, создатели эффективных системных вызовов чтения учитывают этот факт и организуют свой код таким образом, чтобы освободить процессор для других программ на то время, когда процесс чтения находится в ожидании.
Рассмотрим некий процесс ядра Oracle, выполняющий системный вызов чтения для получения блока данных Oracle с диска. После выдачи запроса к предположительно «медленному» устройству, код системного вызова read переведет вызывающий процесс в состояние ожидания (sleep), в котором процесс будет ожидать прерывания, оповещающего о завершении операции ввода/вывода. Такая учтивость со стороны процесса позволяет другому готовому к выполнению (ready to run) процессу занять те циклы процессора, которые в любом случае не были бы доступны процессу чтения.
Когда устройство ввода/вывода сигнализирует о готовности операции ввода/вывода ожидающего процесса к дальнейшей обработке, процесс активизируется, т. е. переходит в состояние готовности к выполнению. А с процессом, готовым к выполнению, может работать планировщик. Этот процесс, выбранный планировщиком для исполнения, будет возвращен в привилегированный режим, в котором и будет выполнена оставшаяся часть кода вызова read (например, передача данных, полученных от канала ввода/вывода, в оперативную память). Последняя инструкция подпрограммы read возвращает управление вызывающей программе (нашему процессу ядра Oracle), т. е. процесс переходит обратно в пользовательский режим. В этом состоянии процесс ядра Oracle продолжает потреблять время процессора в непривилегированном режиме до тех пор, пока не возникнет следующее прерывание и не будет сделан очередной системный вызов.
Надо сказать, что вызов exit тоже относится к системным, поэтому даже когда приложение заканчивает свою работу, единственными способами выхода из пользовательского режима являются системный вызов и переход по прерыванию.
Второй путь в схеме состояний процессов операционной системы образован переходами по прерыванию (interrupt). Прерывание - это механизм, посредством которого периферийное устройство ввода/вывода, системные часы или какое-то другое устройство может асинхронно прервать работу процессора [Bach (1986) 16]. Я уже говорил о том, почему периферийное устройство ввода/вывода может прервать процесс. Конфигурация большинства систем такова, что системные часы поро
ждают прерывание каждую сотую долю секунды (т. е. раз в сантисе-кунду). По получении прерывания от таймера каждый процесс системы, находящийся в пользовательском режиме, сохраняет свой контекст (образ того, чем занимался процесс) и выполняет специальную подпрограмму операционной системы - планировщик (scheduler). Планировщик определяет, следует ли позволить процессу продолжить выполнение или же произвести его вытеснение.
Прерывание обслуживания (preemption) переводит процесс из привилегированного состояния в состояние готовности к выполнению, освобождая тем самым путь для возвращения какого-то другого процесса из состояния готовности к выполнению в пользовательский режим [Bach (1986) 148]. Именно таким образом большая часть современных операционных систем реализует разделение времени. Любой процесс, находящийся в состоянии готовности к выполнению, обрабатывается именно так, как было описано: процесс становится доступным планировщику и т. д. Понимание вытеснения (приоритетного прерывания обслуживания) по таймеру необходимо для осознания материала, изложенного далее в главе при описании одной из основных причин «пропуска данных» в файле трассировки Oracle.
Другие состояния и переходы
Я уже упоминал о существовании более сложной схемы переходов между состояниями процесса, чем та, которая приведена на рис. 7.1. Действительно, обсудив четыре состояния процесса и семь переходов, представленных на рис. 7.1, Бах далее в своей книге приводит более сложную схему переходов состояний процессов [Bach (1986) 148]. На этой схеме подробно рассмотрены действия, выполняемые во время переходов: вытеснение, подкачка, ветвление и даже создание процессов-зомби. Тем, чьи приложения работают в Unix-системах, я бы настойчиво рекомендовал добавить в свою библиотеку книгу Баха.
Для рассмотрения оставшегося материала главы нам будем вполне достаточно рис. 7.1. Надеюсь, вы согласитесь с тем, что изображенные на нем состояния процессов упрощают понимание временных статистик Oracle.
< Предыдущая | Следующая > |
---|