Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Смерь процесса (вызов exitQ)
Рис. 3.1. Жизненный цикл процесса Эта глава рассматривает все эти состояния и переход между ними. Планировщик управляет выбором и исключением процессов, выполняемых процессором. Гл. 7, «Планировщик и синхронизация ядра», описывает планировщик подробнее. Программа содержит множество компонентов, которые располагаются в памяти и запрашиваются процессом, исполняющим программу. Сюда входят текстовый сегмент, который содержит инструкции, выполняемые процессором; сегменты данных, которые содержат переменные, которыми манипулирует процесс; стек, который хранит автоматические переменные и данные функций; и кучу (heap), которая содержит динамически выделенную память. При создании процесса дочерний процесс получает копию родительного пространства данных, кучу, стек и дескриптор (описатель) процесса (process descriptor). Следующий раздел посвящен более детальному описанию дескриптора процесса Linux. Процесс можно объяснить несколькими способами. Наш подход заключается в том, чтобы начать с высокоуровневого рассмотрения выполнения процесса и проследить его до уровня ядра, попутно объясняя назначение вспомогательных структур, которые это обеспечивают. Как программисты, мы знакомы с написанием, компиляцией и выполнением программ. Но как они связаны с процессами? На протяжении этой главы мы обсудим пример программы, которую мы проследим от ее создания до выполнения своих основных задач. В этом случае процесс оболочки Bash создает процесс, становящийся экземпляром нашей программы; в свою очередь, наша программа порождает экземпляр дочернего процесса. До того как мы перейдем к обсуждению процессов, нам нужно ввести несколько соглашений. Обычно мы используем слово процесс и слово задача для описания одного и того же. Когда мы говорим о выполняемом процессе, мы говорим о процессе, который выполняется процессором в данный момент. Глава 3 • Процессы: принципиальная модель выполнения Пользовательский режим против режима ядра Что мы имеем в виду, когда говорим, что программа выполняется в пользовательском режиме или в режиме ядра? Во время жизненного цикла процесса он выполняет как собственный код, так и код ядра. Код считается кодом ядра, когда делается системный вызов, возникает исключение или происходит прерывание (и мы выполняем обработчик прерывания). Любой код, исполняемый процессом и не являющийся системным вызовом, считается кодом пользовательского режима. Такой процесс запускается в пользовательском режиме, и на него налагаются некоторые процессорные ограничения. Если процесс находится внутри системного вызова, мы можем сказать, что он выполняется в режиме ядра. С аппаратной точки зрения код ядра для процессоров Intel выполняется в кольце 0, а на PowerPC он выполняется в супервизорском режиме (supervisor mode). Представление нашей программы В этом разделе представлена программа-пример под названием createjprocess. Этот пример С-программы иллюстрирует различные состояния, в которых может находиться процесс, системные вызовы (которые генерируют перемещение между этими состояниями) и манипуляцию объектами ядра, которые поддерживают выполнение процессов. Идея заключается в получении глубокого понимания того, как программа превращается в процесс и как операционная система обрабатывает эти процессы. create_process.с 1 #include < stdio.h> 2 #include < sys/types.h> 3 #include < sys/stat.h> 4 #include < fcntl.h> 5
6 int main(int argc, char *argv[]) 7 {
8 int fd; 9 int pid; 11
12 pid = forkO; 13 if (pid == 0) 14 {
15 execle(" /bin/ls", NULL); 16 exit(2); 17 } 19 if (waitpid(pid) < 0) 20 printf(" wait error\n" ); Описатель процесса 22 pid = fork(); 23 if (pid == 0){
24 fd=open(" Chapter_03.txt", 0_RDONLY); 25 close(fd); 26 } 2 8 if(waitpid(pid)< 0) 29 printf(" wait error\n" ); 32 exit(0); 33 } Эта программа определяет контекст выполнения, включающий информацию о ресурсах, необходимых для удовлетворения требований, определяемых программой. Например, в каждый момент процессор выполняет только одну инструкцию, извлеченную из памяти1. Тем не менее эта инструкция не будет иметь смысла, если она не окружена контекстом, из которого становится ясно, как инструкция соотносится с логикой программы. Процесс обладает контекстом, составленным из значений, хранимых в счетчиках программы, регистрах, памяти и файлах (или используемом аппаратном обеспечении). Эта программа компилируется и собирается в исполнимый файл, содержащий всю информацию, необходимую для выполнения программы. Гл. 9, «Сборка ядра Linux», уточняет разделение адресного пространства программы и то, как эта информация связана с программой, когда мы обсуждаем образы процессов и бинарные форматы. Процесс содержит несколько характеристик, которые описывают этот процесс и делают его уникальным среди остальных процессов. Характеристики, необходимые для управления процессом, хранятся в одном типе данных, называемом процессорным описателем (process descriptor). Перед тем как углубиться в управление процессами, нам нужно познакомиться с этим описателем процесса. Описатель процесса В ядре описатель процесса представлен структурой под названием task_struct, которая хранит атрибуты и информацию о процессе. Здесь можно найти всю информацию ядра, связанную с процессом. На протяжении жизненного цикла процесса на процесс влияют многие аспекты ядра, такие, как управление памятью и планировщик. Описатель процесса хранит информацию, связанную с этим взаимодействием, вместе со стандартными UNIX-атрибутами процесса. Ядро хранит все описатели процессов в циклическом двусвязном списке, называемом task_list. Также ядро хранит указатель на task_ 1 Повторный вызов сегмента теста, указанного ранее. Глава 3 • Процессы: принципиальная модель выполнения struct текущего выполняемого процесса в глобальной переменной current. (Мы будем вспоминать current на протяжении книги, когда будем говорить о текущем выполняемом процессе.) Процесс может состоять из одного или нескольких потоков. Каждый поток имеет ассоциированную с ним task_struct, включающую уникальный ГО. Потоки одного процесса разделяют адресное пространство этого процесса. Следующие категории описывают некоторые типы элементов описателя процесса, за которыми необходимо следить на протяжении его жизненного цикла: • атрибуты процесса, • связи процесса, • пространство памяти процесса, • управление файлами, • управление сигналами, • удостоверение процесса, • ресурсные ограничения, • поля, связанные с планировкой. Теперь мы подробнее рассмотрим поля структуры task_struct. Этот раздел описывает, для чего они нужны и в каких реальных действиях эти поля участвуют. Многие из них используются для вышеупомянутых задач, остальные выходят за пределы рассмотрения этой книги. Структура task_struct определена в include/linux/ sched.h: include/linux/sched.h 3 84 struct task__struct { 385 volatile long state; 3 86 struct thread_info *thread_info; 387 atomic__t usage; 3 88 unsigned long flags; 3 89 unsigned long ptrace; 3 91 int lock_depth; 393 int prio, static_prio; 3 94 struct list_head run_list; 3 95 prio_array__t *array; 3 97 unsigned long sleep_avg; 3 98 long interactive_credit; Описатель процесса 3 99 unsigned long long timestamp; 402 unsigned long policy; 403 cpumask_t cpus_allowed; 404 unsigned int time_slice, first_time_slice; 405
406 struct list_Jiead tasks; 407 struct list_head ptrace_children; 408 struct list_head ptrace_list; 409 410 struct mm_struct *mm, *active_mm; 413 struct linux__binfmt *binfmt; 414 int exit_code, exit_jsignal; 415 int pdeath_signal;
419 pid_t pid; 420 pid_t tgid;
426 struct task__struct *real_parent; 427 struct task_struct *parent; 428 struct list_head children; 429 struct list_head sibling; 430 struct task_struct *group_leader; 433 struct pid___link pids[PIDTYPE_MAX]; 43 5 wait_queue_head_t wait_chldexit; 43 6 struct completion *vfork_done; 437 int _ user *set_child_tid; 438 int _ user *clear_child_tid; 440 unsigned long rt_priority; 441 unsigned long it_real_value, it_prоrevalue, it__virt_value; 442 unsigned long it_real_incr, it_prof._incr, it_virt_incr; 443 struct timer_list real__timer; 444 unsigned long utime, stime, cutime, cstime; 445 unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; 446 u64 start_time;
450 uid__t uid, euid, suid, f suid; 451 gid_t gid, egid, sgid, fsgid; 452 struct group_info *group_info; 453 kernel_cap_t cap_effective, cap_inheritable, cap__permitted; 4 54 int keep_capabilities: 1; Глава 3 • Процессы: принципиальная модель выполнения 455 struct user_struct *user; 457 struct rlimit rlim[RLIM_NLIMITS]; 458 unsigned short used_math; 459 char coram[16]; 461 int link_count, total_link_count; 467 struct fs__struct *fs; 469 struct files_struct *files; 509 unsigned long ptrace_message; 510 siginfo_t *last__siginfo; 516 }; Популярное:
|
Последнее изменение этой страницы: 2016-03-25; Просмотров: 782; Нарушение авторского права страницы