Читаем Разработка ядра Linux полностью

Это максимальное значение является важным, потому что оно определяет максимальное количество процессов, которые одновременно могут существовать в системе. Хотя значения 32768 и достаточно для офисного компьютера, для больших серверов может потребоваться значительно больше процессов. Чем меньше это значение, тем скорее нумерация процессов будет начинаться сначала, что приводит к нарушению полезного свойства: больший номер процесса соответствует процессу, который запустился позже. Если есть желание нарушить в системе обратную совместимость со старыми приложениями, то администратор может увеличить это максимальное значение во время работы системы с помощью записи его в файл /proc/sys/kernel/pid_max.

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

Для платформы x86 значение параметра current вычисляется путем маскирования 13 младших бит указателя стека для получения адреса структуры thread_info. Это может быть сделано с помощью функции current_thread_info(). Соответствующий код на языке ассемблера показан ниже.

movl $-8192, %eax

andl %esp, %eax

Окончательно значение параметра current получается путем разыменования значения поля task полученной структуры thread_info:

current_thread_info()->task;

Для контраста можно сравнить такой подход с используемым на платформе PowerPC (современный процессор на основе RISC-архитектуры фирмы IBM), для которого значение переменной current хранится в регистре процессора r2. На платформе PPC такой подход можно использовать, так как, в отличие от платформы x86, здесь регистры процессора доступны в изобилии. Так как доступ к дескриптору процесса — это очень частая и важная операция, разработчики ядра для платформы PPC сочли правильным пожертвовать одним регистром для этой цели.

Состояние процесса

Поле state дескриптора процесса описывает текущее состояние процесса (рис. 3.3). Каждый процесс в системе гарантированно находится в одном из пяти различных состояний.

Рис. 3.3. Диаграмма состояний процесса

Эти состояния представляются значением одного из пяти возможных флагов, описанных ниже.

• TASK_RUNNING — процесс готов к выполнению (runnable). Иными словами, либо процесс выполняется в данный момент, либо находится в одной из очередей процессов, ожидающих на выполнение (эти очереди, runqueue, обсуждаются в главе 4. "Планирование выполнения процессов").

• TASK_INTERRUPTIBLE — процесс приостановлен (находится в состоянии ожидания, sleeping), т.е. заблокирован в ожидании выполнения некоторого условия. Когда это условие выполнится, ядро переведет процесс в состояние TASK_RUNNING. Процесс также возобновляет выполнение (wake up) преждевременно при получении им сигнала.

• TASK_UNINTERRUPTIBLE — аналогично TASK_INTERRUPTIBLE, за исключением того, что процесс не возобновляет выполнение при получении сигнала. Используется в случае, когда процесс должен ожидать беспрерывно или когда ожидается, что некоторое событие может возникать достаточно часто. Так как задача в этом состоянии не отвечает на сигналы, TASK_UNINTERRUPTIBLE используется менее часто, чем TASK_INTERRUPTIBLE[13].

• TASK_ZOMBIE — процесс завершен, однако порождающий его процесс еще не вызвал системный вызов wait4(). Дескриптор такого процесса должен оставаться доступным на случай, если родительскому процессу потребуется доступ к этому дескриптору. Когда родительский процесс вызывает функцию wait4(), то такой дескриптор освобождается.

• TASK_STOPPED — выполнение процесса остановлено. Задача не выполняется и не имеет право выполняться. Такое может случиться, если задача получает какой-либо из сигналов SIGSTOP, SIGTSTP, SIGTTIN или SIGTTOU, а также если сигнал приходит в тот момент, когда процесс находится в состоянии отладки.

Перейти на страницу:

Похожие книги

C++: базовый курс
C++: базовый курс

В этой книге описаны все основные средства языка С++ - от элементарных понятий до супервозможностей. После рассмотрения основ программирования на C++ (переменных, операторов, инструкций управления, функций, классов и объектов) читатель освоит такие более сложные средства языка, как механизм обработки исключительных ситуаций (исключений), шаблоны, пространства имен, динамическая идентификация типов, стандартная библиотека шаблонов (STL), а также познакомится с расширенным набором ключевых слов, используемым в .NET-программировании. Автор справочника - общепризнанный авторитет в области программирования на языках C и C++, Java и C# - включил в текст своей книги и советы программистам, которые позволят повысить эффективность их работы. Книга рассчитана на широкий круг читателей, желающих изучить язык программирования С++.

Герберт Шилдт

Программирование, программы, базы данных