Лабораторная работа "Управление процессами" - efanov/mephi GitHub Wiki

Содержание

Цель

Изучить свойства процессов и средства управления процессами.

После выполнения лабораторной студент должен знать следующие аспекты процессов:

  1. Командный интерфейс мониторинга процессов.
  2. Возможности файловой системы procfs.
  3. Механизм заданий (jobs). Выполнение процесса в основном и фоновом режимах.
  4. Взаимодействие процесса с виртуальной файловой системой.
  5. Средства взаимодействия процессов (механизм сигналов).
  6. Жизненный цикл процесса (системные вызовы fork->exec->wait->exit).

Команды, изучаемые в лабораторной работе: ps, top, pgrep, pstree, w, uptime, jobs, fg, bg, kill, killall, pkill, trap.

Системные вызовы, изучаемые в лабораторной работе: fork(), execve(), wait(), exit(), sigaction().

Задание

Мониторинг процессов

Получение информации о процессах с помощью команд

  1. Выведите информацию обо всех процессах в системе, используя стандартный синтаксис:

      $ ps -e
      $ ps -ef
      $ ps -eF
      $ ps -ely
    
  2. Выведите информацию обо всех процессах в системе, используя синтаксис BSD:

      $ ps ax
      $ ps axu
    
  3. Выведите информацию обо всех процессах в системе в виде дерева:

      $ ps -ejH
      $ ps axjf
    
  4. Выведите информацию о легковесных процессах:

      $ ps -eLf
      $ ps axms
    
  5. Выведите атрибуты безопасности процессов разными способами:

      $ ps -eo euser,ruser,suser,fuser,f,comm,label
      $ ps axZ
      $ ps -eM
    
  6. Выведите информацию о процессах, выполняющихся от имени пользователя root (real & effective ID), в пользовательском формате:

      $ ps -U root -u root u
    
  7. Выведите информацию о процессах в пользовательском формате:

      $ ps -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,wchan:14,comm
      $ ps axo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm
      $ ps -Ao pid,tt,user,fname,tmout,f,wchan
    
  8. Выведите только идентификаторы процессов с именем systemd:

      $ ps -C systemd -o pid=
    
  9. Выведите только имя процесса с заданным идентификатором PID:

      $ ps -q <PID> -o comm=
    

Мониторинг процессов с помощью файловых систем procfs и sysfs

Обратите внимание: в переменной $ хранится PID текущего процесса. Поэтому вместо конструкции $$ bash подставит собственный PID.

  1. Изучите содержимое файла /proc/version и сравните с выводом команды uname -a.

  2. Изучите и сравните содержимое файлов /proc/meminfo и /sys/devices/system/node/node0/meminfo, и вывод команды free.

  3. Изучите содержимое файла /proc/cpuinfo. Определите количество ядер.

  4. Изучите содержимое файла /proc/uptime и сравните с выводом команды uptime.

  5. Изучите специальную символьную ссылку /proc/self, которая указывает на директорию текущего (self) процесса. Объясните результаты.

      $ echo $$
      3203
      $ ls -l /proc/self
      lrwxrwxrwx. 1 root root 0 Oct 13 21:42 /proc/self -> 12485
    
  6. Изучите содержимое файла /proc//status.

      $ cat /proc/$$/status
      Name:	bash
      Umask:	0002
      State:	S (sleeping)
      Tgid:	8266
      Ngid:	0
      Pid:	8266
      PPid:	8260
      TracerPid:	0
      Uid:	1000	1000	1000	1000
      Gid:	1000	1000	1000	1000
      FDSize:	256
      Groups:	10 1000 
      ...
    
  7. Изучите содержимое файла /proc//stat. Формат вывода можно посмотреть в исходном коде ядра Linux в файле /fs/proc/array.c в функции do_task_stat(). Пример:

      $ read pid tcomm state other < /proc/$$/stat
      $ echo "Процесс $pid $tcomm находится в состоянии $state"
      Процесс 3203 (bash) находится в состоянии R
    

Механизм заданий (jobs). Выполнение процесса в основном и фоновом режимах

  1. Откройте два окна терминала (левый и правый).

  2. В левом окне запустите бесконечный процесс, который с интервалом в одну секунду будет писать строку AAA в файл test.out в домашнем каталоге.

      $ ( while true; do printf "AAA %d " $$ >> ~/test.out; sleep 1; done )
    
  3. В правом окне наблюдайте за работой процесса.

      $ tail -f ~/test.out
    
  4. В левом окне остановите процесс. BASH вернет номер задания в квадратных скобках. Убедитесь, что процесс перестал писать в файл. Обратите внимание, что изменилось состояние процесса (ps j).

      $ Ctrl+z
    
  5. В левом окне выведите список заданий. Знаком + помечено текущее задание. Определите состояние процесса. Запустите задание в фоновом режиме. Убедитесь, что процесс снова продолжил писать в файл. Определите состояние процесса ещё раз.

      $ jobs
      $ ps j
      $ bg
      $ jobs
      $ ps j
    
  6. В левом окне запустите второй бесконечный процесс в фоновом режиме, который с интервалом в одну секунду будет писать строку UUU в файл test.out в домашнем каталоге. Команда должна быть заключена в круглые скобки и заканчиваться знаком &.

      $ ( while true; do printf "UUU %d " $$ >> ~/test.out; sleep 1; done ) &
    
  7. В левом окне выведите список заданий. Убедитесь, что теперь два процесса пишут в файл.

      $ jobs
    
  8. В левом окне завершите процессы.

      $ fg %номер
      $ Ctrl+c
      $ fg %номер
      $ Ctrl+c
    
  9. В правом окне завершите команду tail.

Механизм сигналов

Посылка сигналов процессам

  1. Откройте два окна терминала (левый и правый).

  2. В левом окне запустите два бесконечных процесса, которые с интервалом в одну секунду будут писать строки в файл test.out в домашнем каталоге. Выведите список заданий (наблюдайте Running). Определите состояние процессов.

      $ ( while true; do printf "AAA %d " $$ >> ~/test.out; sleep 1; done ) &
      $ ( while true; do printf "UUU %d " $$ >> ~/test.out; sleep 1; done ) &
      $ jobs
      $ ps j
    
  3. В правом окне наблюдайте за работой процессов.

      $ tail -f ~/test.out
    
  4. В левом окне остановите первый процесс (задание "AAA"). Выведите список заданий (наблюдайте Stopped).

      $ kill -SIGSTOP %1
      $ jobs
    
  5. В левом окне завершите второй процесс (задание "UUU"). Выведите список заданий (наблюдайте Terminated).

      $ kill -SIGTERM %2
      $ jobs
    
  6. В левом окне завершите процесс.

      $ fg
      $ Ctrl+c
    
  7. В правом окне завершите команду tail.

Изучение команд trap и sleep

Команда trap позволяет установить обработчик на сигнал. Опция -l выводит список сигналов. Опция -p выводит установленные обработчики сигналов.

  1. Выведите список сигналов.

      $ trap -l
       1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
       6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
      11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
      16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
      21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
      26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
      31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
      38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
      43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
      48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
      53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
      58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
      63) SIGRTMAX-1	64) SIGRTMAX
    
  2. Запустите дочерний shell и установите обработчик сигнала EXIT (0, который посылается нажатием Ctrl+d).

      $ sh
      sh-4.3$ trap 'echo Завершение работы...; sleep 2' EXIT
      sh-4.3$ trap -p EXIT
      trap -- 'echo Завершение работы...; sleep 2' EXIT
    
  3. Завершите shell.

      $ Ctrl+d
    
  4. Наблюдайте перехват сигнала и вызов обработчика.

  5. Создайте сценарий.

      $ cat test-trap.sh
      #!/bin/bash
      declare -i i=0
      trap 'echo "Аварийное завершение..."; exit 1' SIGINT
      while [ $i -lt 100 ]
      do
      	(( i++ ))
      	echo $i
      	sleep 1
      done
    
  6. Запустите сценарий.

      $ chmod +x test-trap.sh
      $ ./test-trap.sh
    
  7. Завершите сценарий. Объясните результаты.

      $ Ctrl+C
    

Работа процесса с файлами

Дескрипторы открытых файлов процесса

  1. Изучите различные формы обращения к файловым дескрипторам и потокам stdin, stdout, stderr.

      $ ls -l /dev/std*
      lrwxrwxrwx. 1 root root 15 Oct 13 21:42 /dev/stderr -> /proc/self/fd/2
      lrwxrwxrwx. 1 root root 15 Oct 13 21:42 /dev/stdin -> /proc/self/fd/0
      lrwxrwxrwx. 1 root root 15 Oct 13 21:42 /dev/stdout -> /proc/self/fd/1
      $ ls -l /dev/fd/
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 2 -> /dev/pts/0
      lr-x------. 1 defanov defanov 64 Oct 14 00:31 3 -> /proc/13123/fd
    
  2. Изучите список открытых файлов процесса. Определите потоки stdin, stdout, stderr.

      $ ls -l /proc/self/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:07 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:07 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:07 2 -> /dev/pts/0
      lr-x------. 1 defanov defanov 64 Oct 14 00:07 3 -> /proc/12898/fd
    
  3. Перенаправьте потоки stdout и stderr в файлы. Объясните результаты.

      $ ls -l /proc/self/fd > /tmp/ls.out 2> /tmp/ls.err
      $ cat /tmp/ls.out 
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:09 0 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 00:09 1 -> /tmp/ls.out
      l-wx------. 1 defanov defanov 64 Oct 14 00:09 2 -> /tmp/ls.err
      lr-x------. 1 defanov defanov 64 Oct 14 00:09 3 -> /proc/12915/fd
    
  4. Перенаправьте поток stdin. Объясните права доступа.

Взаимодействие параллельных процессов через каналы

  1. Откройте два окна терминала (левый и правый).

  2. В левом окне (TTY == pts/0) запустите конвейер (неименованный канал), перенаправьте потоки stdout и stderr в файлы в домашнем каталоге.

     $ ( cat | head ) > ~/test.out 2> ~/test.err
    
  3. В правом окне (TTY == pts/1) выведите дескрипторы открытых файлов процессов bash, cat и head.

     $ ps j --forest
        PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
       47414   47418   47418    8758 pts/1      47792 S     1001   0:00 -bash
       47418   47792   47792    8758 pts/1      47792 R+    1001   0:00  \_ ps j --forest
       47199   47203   47203    6634 pts/0      47771 S     1001   0:00 -bash
       47203   47771   47771    6634 pts/0      47771 S+    1001   0:00  \_ -bash
       47771   47772   47771    6634 pts/0      47771 S+    1001   0:00      \_ cat
       47771   47773   47771    6634 pts/0      47771 S+    1001   0:00      \_ head
     $ ls -l /proc/47771/fd
     total 0
     lrwx------. 1 user1 user1 64 Nov 22 21:45 0 -> /dev/pts/0
     l-wx------. 1 user1 user1 64 Nov 22 21:45 1 -> /home/user1/test.out
     l-wx------. 1 user1 user1 64 Nov 22 21:45 2 -> /home/user1/test.err
     $ ls -l /proc/47772/fd
     total 0
     lrwx------. 1 user1 user1 64 Nov 22 21:45 0 -> /dev/pts/0
     l-wx------. 1 user1 user1 64 Nov 22 21:45 1 -> 'pipe:[611050]'
     l-wx------. 1 user1 user1 64 Nov 22 21:45 2 -> /home/user1/test.err
     $ ls -l /proc/47773/fd
     total 0
     lr-x------. 1 user1 user1 64 Nov 22 21:45 0 -> 'pipe:[611050]'
     l-wx------. 1 user1 user1 64 Nov 22 21:45 1 -> /home/user1/test.out
     l-wx------. 1 user1 user1 64 Nov 22 21:45 2 -> /home/user1/test.err
    
  4. Изучите как поток stdout процесса cat связан с потоком stdin процесса head. Обратите внимание на то, что конструкция ( ... | ... ) выполняется в отдельном шелле. Процессы bash, cat и head являются родственными процессами (PID одного равен PPID двух других) и принадлежат к одной группе процессов (PGID == 47771), а лидером группы является процесс bash (PID == PGID == 47771).

  5. В левом окне завершите процессы.

  6. В левом окне создайте именованный канал (FIFO). Какой тип у файла ~/fifo1?

     $ mkfifo ~/fifo1
    
  7. В левом окне запустите команду cat с перенаправлением вывода в созданный канал.

     $ cat > ~/fifo1
    
  8. В правом окне запустите команду cat с перенаправлением ввода из канала.

     $ cat < ~/fifo1
    
  9. Откройте ещё одно (третье) окно терминала и запустите в нём команду cat с перенаправлением ввода из канала.

     $ cat < ~/fifo1
    
  10. В левом окне вводите строки текста и наблюдайте вывод в двух других окнах. Объясните результаты.

  11. Изучите дескрипторы открытых файлов процессов cat. Как связаны их потоки stdout и stdin?

  12. Обратите внимание на то, что через именованные каналы могут общаться неродственные процессы. Объясните почему?

  13. Организуйте чтение из канала в бесконечном цикле while с помощью команды read.

  14. Завершите процессы. Закройте окна терминалов.

Изучение команды exec

Команда exec используется для двух целей: запуск программ и открытие файлов.

  1. Запустите дочерний shell и заместите коды порожденного процесса кодами команды ps -l. Обратите внимание на то, что PID процесса sh совпадает с PID процесса ps (13028). Объясните результаты.

      $ sh
      sh-4.3$ ps -l
      F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
      0 S  1000  3203  3197  0  80   0 - 29691 wait   pts/0    00:00:00 bash
      0 S  1000 13028  3203  0  80   0 - 28960 wait   pts/0    00:00:00 sh
      0 R  1000 13030 13028  0  80   0 - 34450 -      pts/0    00:00:00 ps
      sh-4.3$ exec ps -l
      F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
      0 S  1000  3203  3197  0  80   0 - 29691 wait   pts/0    00:00:00 bash
      0 R  1000 13028  3203  0  80   0 - 34450 -      pts/0    00:00:00 ps
      $ ps -l
      F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
      0 S  1000  3203  3197  0  80   0 - 29691 wait   pts/0    00:00:00 bash
      0 R  1000 13034  3203  0  80   0 - 34450 -      pts/0    00:00:00 ps
    
  2. Исследуйте работу процесса с файлами на примере bash. Откройте файл ~/test.out на запись и свяжите его с дескриптором 3.

      $ exec 3> ~/test.out
      $ ls -l /proc/$$/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:21 2 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 13 21:30 255 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 00:31 3 -> /home/defanov/test.out
      $ echo Test
      Test
      $ echo Test3 >&3
      $ cat ~/test.out 
      Test3
      $ echo Test333 >&3
      $ cat ~/test.out 
      Test3
      Test333
    
  3. Выведите информацию об открытых файлах процесса bash. Объясните позицию указателя чтения/записи (pos: 14).

      $ echo $$
      3203
      $ ls -l /proc/3203/fdinfo/
      total 0
      -r--------. 1 defanov defanov 0 Oct 13 21:30 0
      -r--------. 1 defanov defanov 0 Oct 13 21:30 1
      -r--------. 1 defanov defanov 0 Oct 13 21:30 2
      -r--------. 1 defanov defanov 0 Oct 13 21:30 255
      -r--------. 1 defanov defanov 0 Oct 14 00:40 3
      $ cat /proc/3203/fdinfo/3 
      pos:	14
      flags:	0100001
      mnt_id:	82
    
  4. Откройте файл ~/test.out на чтение и свяжите его с дескриптором 4.

      $ exec 4< ~/test.out 
      $ ls -l /proc/$$/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:21 2 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 13 21:30 255 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 00:31 3 -> /home/defanov/test.out
      lr-x------. 1 defanov defanov 64 Oct 14 00:54 4 -> /home/defanov/test.out
      $ cat ~/test.out 
      Test3
      Test333
      $ cat <&4
      Test3
      Test333
      $ cat ~/test.out 
      Test3
      Test333
      $ cat <&4
      $
      $ echo Test4 >&3
      $ cat ~/test.out 
      Test3
      Test333
      Test4
      $ cat <&4
      Test4
      $ cat <&4
      $
    
  5. Удалите файл ~/test.out.

      $ rm ~/test.out 
      $ ls -l /proc/$$/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:21 2 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 13 21:30 255 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 00:31 3 -> /home/defanov/test.out (deleted)
      lr-x------. 1 defanov defanov 64 Oct 14 00:54 4 -> /home/defanov/test.out (deleted)
    
  6. Попробуйте вывести содержимое файла ~/test.out командой cat, используя два способа обращения к файлу: через дескриптор и через имя. Объясните результат.

Изучение системных вызовов

Жизненный цикл процесса

  1. На портале https://github.com создайте fork репозитория https://github.com/efanov/linux-textbook.

  2. Склонируйте полученный репозиторий на компьютер:

     $ git clone https://github.com/<ваш_login>/linux-textbook
    
  3. Изучите программу p_wait.c. Программа создает процесс-потомка. Если программа запускается без аргумента, то процесс-потомок приостанавливает свое выполнение с помощью системного вызова pause(), чтобы пользователь смог послать ему сигнал. Если программа запускается с аргументом, то процесс-потомок немедленно завершается, передавая значение аргумента в качестве кода возврата. Процесс-родитель в цикле выполняет системный вызов waitpid(), чтобы отслеживать состояние процесса-потомка. С помощью макросов W*() он анализирует значение полученного статуса от процесса-потомка.

  4. Выполните компиляцию и запуск программы. Пример работы с программой:

     $ gcc p_wait.c -o p_wait
     $ ./p_wait &
     Child PID is 32360
     [1] 32359
     $ kill -STOP 32360
     stopped by signal 19
     $ kill -CONT 32360
     continued
     $ kill -TERM 32360
     killed by signal 15
     [1]+  Done    ./p_wait
    
  5. Объясните полученные результаты.

  6. На портале https://github.com создайте fork репозитория https://github.com/efanov/mephi.

  7. Склонируйте полученный репозиторий на компьютер:

     $ git clone https://github.com/<ваш_login>/mephi
    
  8. Изучите содержимое директории processes. Программа p_execve.c запускает (выполняет exec) другую программу, путь к которой передаётся через аргумент командной строки. Программа p_print_argv_env.c предназначена для выполнения программой p_execve.c, она выводит аргументы, с которыми она запущена, и переменные окружения.

  9. Выполните компиляцию и запуск программ:

     $ gcc p_execve.c -o p_execve
     $ gcc p_print_argv_env.c -o p_print_argv_env
     $ ./p_execve ./p_print_argv_env
     argv[0] = p_print_argv_env
     argv[1] = Russia
     argv[2] = Moscow
     environ: University=MEPhI
    
  10. Объясните полученные результаты.

  11. Изучите содержимое директории signals. Программа p_sigaction.c с помощью системного вызова sigaction() изменяет диспозицию сигнала SIGINT.

  12. Выполните компиляцию и запуск программы. Отправляйте процессу сигнал SIGINT, нажимая на клавиатуре Ctrl+C. Для завершения процесса нажмите **Ctrl+**.

     $ make
     $ ./p_sigaction
     ./p_sigaction: PID is 54715
     ^CReceived signal 2 (Interrupt)
     ^CReceived signal 2 (Interrupt)
     ^CReceived signal 2 (Interrupt)
     ^\Quit (core dumped)
     $
    
  13. Объясните полученные результаты.

  14. Запустите программу ещё раз.

  15. Остановите процесс.

  16. Отправьте процессу сигнал SIGINT из командной строки.

  17. Изучите дескриптор процесса.

  18. Завершите процесс.

  19. Пример:

     $ ./p_sigaction
     ./p_sigaction: PID is 54715
     ./p_sigaction: PID is 60922
     ^Z
     [1]+  Stopped                 ./p_sigaction
     $ kill -SIGINT 60922
     $ cat /proc/60922/status 
     Name:	p_sigaction
     Umask:	0002
     State:	T (stopped)
     Pid:	60922
     ...
     SigPnd:	0000000000000000
     ShdPnd:	0000000000000002
     SigBlk:	0000000000000000
     SigIgn:	0000000000000000
     SigCgt:	0000000000000002
     ...
     $ fg
     ./p_sigaction
     Received signal 2 (Interrupt)
     ^\Quit (core dumped)
     $
    
  20. Измените программу таким образом, чтобы сигнал SIGINT игнорировался процессом.

  21. Объясните полученные результаты.

Дополнительное задание. Разработка сценария

  1. Найти в системе все процессы, у которых различаются реальные и эффективные пользовательские идентификаторы.

  2. Для обнаруженных процессов вывести имя программы.

Для тестирования можно использовать программу passwd.

Порядок защиты лабораторной работы

Для защиты работы необходимо ответить на вопросы по выполненным заданиям.

⚠️ **GitHub.com Fallback** ⚠️