netlib.narod.ru | < Назад | Оглавление | Далее > |
PID генерируются функцией get_pid (строка 23611), которая возвращает еще не используемый PID. В качестве начального эта функция использует last_pid (строка 23464) — последний выделенный PID.
Используемая в программе ядра версия функции get_pid служит примером часто применяемых в ядре компромиссов между простотой и быстродействием; в данном случае преимущество отдано быстродействию. Функция get_pid в высшей степени оптимизирована — она гораздо сложнее, чем могла бы быть простая ее реализация, но она и работает гораздо быстрее. Наиболее простая реализация выполняла бы просмотр всего списка задач — как правило состоящего из десятков, а иногда и сотен, записей — для каждого возможного PID, пока не было бы найдено подходящее значение. Иногда анализируемая версия вынуждена просматривать весь список, но в большинстве случаев может его пропускать. Целью такого подхода является ускорение создания процесса — операции, малая скорость которой в Unix общеизвестна.
Если требуется всего лишь быстро вычислить целочисленное значение, отличающееся для каждого выполняющегося процесса, то такое значение уже существует: достаточно получить индекс процесса в массиве task. В среднем это наверняка было бы быстрее, чем прибегать к использованию функции get_pid — в конце концов, при этом никогда не пришлось бы просматривать весь список задач. К сожалению, многие существующие приложения исходят из предположения, что до использования PID должно пройти некоторое время. Такое допущение в любом случае является ненадежным, но, вероятно, не стоит заставлять ядро спорить с такими программами. Существующая стратегия выделения PID все же обеспечивает очень высокое быстродействие и имеет то преимущество, что редко позволяет, если вообще позволяет, проявляться скрытым ошибкам в таких приложениях (если, конечно, считать это преимуществом).
23613: Переменная предназначена для ускорения работы; она отслеживает следующего наименьшего кандидата в PID, который может быть зарезервирован. (Более точным ее именем было бы next_unsafe.) Когда значение last_pid увеличивается выше этого предела, весь список задач должен быть проверен на предмет того, является ли кандидат в PID все еще зарезервированным (процесс, который первоначально зарезервировал его, может уже завершиться), поскольку просмотр всего списка может быть очень медленным, по возможности его следует избегать. Таким образом, выполняя просмотр, функция get_pid повторно вычисляет переменную next_safe — если какой-либо процесс завершился, это значение теперь может быть выше, и, следовательно, функция get_pid может быть в состоянии избежать некоторых будущих просмотров списка задач. (Переменная next_safe является статической и поэтому ее значение будет запомнено, когда функции get_pid в следующий раз потребуется выделить PID.)
23616: Если новый процесс должен использовать PID совместно с его родительским процессом, возвращается PID родительского процесса.
23620: Начинает поиск среди кандидатов в PID на предмет неиспользуемого значения. Поразрядный оператор AND лишь проверяет, не превышает ли новое значение переменной last_pid 32767 (максимальный допустимый PID), проверяя, не равен ли единице любой, кроме младших 15-и разрядов. Сомнительно, что разработчики ядра действительно нуждались в столь незначительном ускорении работы, но утверждать это трудно; по крайней мере, на момент написания этих строк gcc был недостаточно разумным, чтобы заметить эквивалентность и выбрать несколько более быструю форму, использованную в коде.
23621: Если значение переменной last_pid превышает максимальное допустимое для нее значение, оно устанавливается равным 300. Это число лишено какого-либо особого смысла и является всего лишь еще одной попыткой ускорения работы. Идея заключается в том, что PID с низкими номерами как правило принадлежат долговременным «демонам», создаваемым во время начального запуска и никогда не прерывающимся. Поскольку они всегда занимают PID с низкими номерами, неиспользуемый PID будет найден быстрее, если несколько сот начальных значений никогда не будут считаться доступными для повторного использования. Поскольку количество допустимых PID в 64 раза превосходит максимальное количество задач, допускаемых одновременно (512), напрасная трата нескольких из них вполне оправдана во имя повышения быстродействия.
23622: Поскольку значение last_pid превосходит максимальный допустимый PID, оно должно также превосходить значение next_safe; следовательно, следующая проверка if может быть пропущена.
23622: Если значение переменной last_pid все же меньше значения переменной next_safe, ее новое значение доступно для использования. В противном случае необходимо проверить список задач.
23633: Если текущее значение переменной last_pid принято, оно просто увеличивается, при необходимости устанавливаясь равным 300, и цикл запускается снова. На первый взгляд кажется, что этот цикл мог бы продолжаться вечно — что если все PID уже используются? Но недолгие размышления заставляют отмести такую возможность: максимальный размер списка задач равен максимальному количеству одновременно выполняющихся задач, а количество допустимых PID значительно больше этого числа. Следовательно, со временем цикл должен найти допустимый PID; это всего лишь вопрос времени.
23651: Функция get_pid находит незанятый PID, который и возвращается.
netlib.narod.ru | < Назад | Оглавление | Далее > |