Возможно, эти ссылки могут помочь:
- пространства имен PID в работе
- Краткое введение в пространства имен PID (эта один исходит от системного администратора)
После прохождения второй ссылки становится понятно, что пространства имен — отличный способ изолировать ресурсы. И в любой ОС, включая Linux, процессы являются одним из самых важных ресурсов. По его собственным словам
Да, все, с этим пространством имен можно перезапустить нумерацию PID и получить свой процесс «1». Это можно рассматривать как «chroot» в дереве идентификаторов процессов. Это очень удобно, когда вам нужно иметь дело с PID в повседневной работе и застряли с 4-значными числами…
Таким образом, вы как бы создаете собственное частное дерево процессов, а затем назначаете его конкретному пользователю и/или конкретной задаче. Внутри этого дерева процессам не нужно беспокоиться о конфликте PID с PID за пределами этого «контейнера». Следовательно, это так же хорошо, как передать это дерево другому «корневому» пользователю. Этот прекрасный парень проделал замечательную работу по объяснению вещей с помощью небольшого милого примера в довершение всего, поэтому я не буду повторяться здесь.
Что касается ядра, я могу дать вам несколько советов для начала. Я не эксперт здесь, но я надеюсь, что это должно помочь вам в некоторой степени.
В этой статье LWN описывается старый и новый взгляд на PID. Своими словами:
Все PID, которые могут быть у задачи, описаны в файле struct pid
. Эта структура содержит значение идентификатора, список задач, имеющих этот идентификатор, счетчик ссылок и узел хешированного списка, который необходимо сохранить в хеш-таблице для более быстрого поиска. Еще несколько слов о списках задач. По сути, задача имеет три идентификатора PID: идентификатор процесса (PID), идентификатор группы процессов (PGID) и идентификатор сеанса (SID). PGID и SID могут совместно использоваться задачами, например, когда две или более задач принадлежат одной группе, поэтому каждый идентификатор группы относится к более чем одной задаче. С пространствами имен PID эта структура становится гибкой. Теперь у каждого PID может быть несколько значений, каждое из которых допустимо в одном пространстве имен. То есть задача может иметь PID 1024 в одном пространстве имен и 256 в другом. Итак, бывший struct pid
меняется. Вот как выглядело struct pid
до введения пространств имен PID:
struct pid {
atomic_t count; /* reference counter */
int nr; /* the pid value */
struct hlist_node pid_chain; /* hash chain */
struct hlist_head tasks[PIDTYPE_MAX]; /* lists of tasks */
struct rcu_head rcu; /* RCU helper */
};
А вот как это выглядит сейчас:
struct upid {
int nr; /* moved from struct pid */
struct pid_namespace *ns; /* the namespace this value
* is visible in */
struct hlist_node pid_chain; /* moved from struct pid */
};
struct pid {
atomic_t count;
struct hlist_head tasks[PIDTYPE_MAX];
struct rcu_head rcu;
int level; /* the number of upids */
struct upid numbers[0];
};
Как видите, struct upid
теперь представляет значение PID -- оно хранится в хеше и имеет значение PID. Чтобы преобразовать struct pid
в PID или наоборот, можно использовать набор помощников, таких как task_pid_nr()
, pid_nr_ns()
, find_task_by_vpid()
и т. д.
Хотя эта информация немного устарела, она достаточно справедлива, чтобы вы могли начать. Здесь нужно упомянуть еще одну важную структуру. Это struct nsproxy
. Эта структура является фокусом всего пространства имен по отношению к процессам, с которыми она связана. Он содержит указатель на пространство имен PID, которое будут использовать дочерние процессы этого процесса. Пространство имен PID для текущего процесса находится с помощью task_active_pid_ns
.
Внутри struct task_struct
у нас есть прокси-указатель пространства имен с метким названием nsproxy
, который указывает на структуру struct nsproxy
этого процесса. Если вы проследите шаги, необходимые для создания нового процесса, вы сможете найти отношения между task_struct
, struct nsproxy
и struct pid
.
Новый процесс в Linux всегда разветвляется из существующего процесса, а его образ позже заменяется с помощью execve
(или аналогичных функций из семейства exec). Таким образом, как часть do_fork
вызывается copy_process
.
В рамках копирования родительского процесса происходят следующие важные вещи:
task_struct
сначала дублируется с помощью dup_task_struct
.
- пространства имен родительского процесса также копируются с использованием
copy_namespaces
. Это также создает новую структуру nsproxy
для дочернего элемента, и его указатель nsproxy указывает на эту вновь созданную структуру.
Для процесса, отличного от INIT (исходный глобальный PID, также известный как первый процесс, созданный при загрузке), структура PID
выделяется с использованием alloc_pid
, что фактически выделяет новую структуру PID для нового процесса fork
ed. Короткий фрагмент этой функции:
nr = alloc_pidmap(tmp);
if(nr<0)
goto out_free;
pid->numbers[i].nr = nr;
pid->numbers[i].ns = tmp;
Это заполняет структуру upid
, присваивая ей новый PID, а также пространство имен, которому она в настоящее время принадлежит.
Кроме того, как часть функции copy process
, этот вновь выделенный PID затем связывается с соответствующим task_struct
через функцию pid_nr
, т. е. его глобальный идентификатор (который является исходным номером PID, как видно из пространства имен INIT) сохраняется в поле pid
в task_struct
.
На заключительных этапах copy_process
устанавливается связь между task_struct
и этой новой структурой pid
через поле pid_link
внутри task_struct
через функцию attach_pid
.
Это еще не все, но я надеюсь, что это даст вам хоть какой-то старт.
ПРИМЕЧАНИЕ. Я имею в виду последнюю (на данный момент) версию ядра, а именно. 3.17.2.
person
HighOnMeat
schedule
10.11.2014