Аргумент ctid представляет собой механизм, с помощью которого библиотека NPTL получает уведомление о завершении потока. Это уведомление необходимо для функции pthread_join(), которая позволяет одному POSIX-потоку ждать завершения другого.

При создании потока с помощью функции pthread_join() библиотека NPTL делает вызов clone(), в котором аргументы ptid и ctid указывают на один и тот же участок памяти (именно по этой причине CLONE_CHILD_SETTID не входит в состав NPTL). Благодаря флагу CLONE_PARENT_SETTID этот участок инициализируется идентификатором нового потока. Когда потомок завершает работу, а ctid очищается, данное изменение доступно всем потокам в процессе (поскольку был дополнительно указан флаг CLONE_VM).

Ядро обращается с участком памяти, на который указывает ctid, как с фьютексом — высокопроизводительным механизмом синхронизации (больше подробностей о фьютексах можно узнать на справочной странице futex(2)). Уведомление о завершении потока можно получить с помощью системного вызова futex(), который блокирует ожидание изменения в содержимом участка памяти, связанного с ctid (внутри происходит то же самое, что и в функции pthread_join()). В то же время ядро очищает ctid и возобновляет работу любых единиц планирования ядра (то есть потоков), заблокированных из-за ожидания фьютексом этого адреса (на уровне POSIX-потоков это приводит к разблокированию с помощью вызова pthread_join()).

Локальное хранилище на уровне потока: CLONE_SETTLS

Если указать флаг CLONE_SETTLS, аргумент tls будет указывать на структуру user_desc, описывающую буфер локального хранилища, которое будет использоваться в этом потоке. Этот флаг был добавлен в Linux 2.6 для поддержки локальных хранилищ на уровне потока в библиотеке NPTL (см. раздел 31.4). Подробные сведения о структуре user_desc можно почерпнуть в исходных кодах ядра версии 2.6 и на справочной странице set_thread_area(2).

Отдельные пространства имен файловой системы для каждого процесса: CLONE_NEWNS

Начиная с версии 2.4.19, ядро Linux поддерживает отдельные пространства имен файловой системы для каждого процесса, которые представляют собой набор точек подключения, обслуживаемых вызовами mount() и umount(). Пространство имен файловой системы отвечает за то, каким образом из путей получаются соответствующие файлы, а также за работу таких системных вызовов, как chdir() и chroot().

Родитель и потомок по умолчанию используют общее пространство имен файловой системы. Это означает, что изменения, внесенные с помощью mount() и umount() в одном процессе будут видны другому (как в случае с fork() и vfork()). Привилегированный процесс (CAP_SYS_ADMIN) может указать флаг CLONE_NEWNS, чтобы потомок получил копию пространства имен ФС своего родителя. В результате этого изменения будут доступны только тому процессу, который их вносит (в ядрах версий 2.4.x и ниже можно считать, что все процессы в системе работают с единым системным пространством имен ФС).

С помощью разделения пространств имен ФС можно создавать изолированные среды, похожие на «тюрьмы» chroot() (chroot jails), но более безопасные и гибкие; например, изолированному процессу можно предоставить точку подключения, недоступную для любого другого процесса в системе. Пространства имен ФС также могут пригодиться при создании среды для виртуального сервера.

Одновременное использование флагов CLONE_NEWNS и CLONE_FS в одном и том же вызове clone() не имеет смысла и является недопустимым.

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

Родителем процесса, который создается с помощью clone() (и который соответствует значению, возвращаемому вызовом getppid()), по умолчанию является процесс, вызвавший clone() (как в случае с fork() и vfork()). Но если указать флаг CLONE_PARENT, родителем потомка будет родитель вызывающего процесса. Иными словами, флаг CLONE_PARENT тождественен присваиванию child.PPID = caller.PPID (в стандартной ситуации, без флага CLONE_PARENT, это выглядело бы как child.PPID = caller.PID). Родительским (child.PPID) является процесс, которому приходит сигнал при завершении потомка.

Флаг CLONE_PARENT доступен в Linux 2.4 и выше. Изначально он задумывался для удобства реализации POSIX-потоков, однако в ядре версии 2.6 был сделан акцент на вспомогательных потоках (с применением флага CLONE_THREAD, описанного выше), благодаря чему необходимость в данном флаге отпала.

Назначение потомку идентификатора его родителя: CLONE_PID (устаревший)

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

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