Procesy

Procesy – obserwacja

Dla administratora w jego codziennej działalności najporęczniejszą komendą do obserwacji procesów w systemie jest top|htop. Do uzyskania obrazu całego drzewa genealogicznego procesów wygodnie jest użyć komendy pstree -[ch].

Podstawową komendą do szczegółowej analizy działania procesów w systemie jest ps (zob. man ps). Korzystając z tej komendy można używać opcji podawanych w stylu UNIX, BSD oraz GNU.

Obserwacja procesów związanych z daną sesją:

# ps
# ps -w
# ps -f|F
# ps -f -t tty1
# ps -fw
# ps -l
# ps -lf
# ps -L[f]
# ps -Fl

Obserwacja procesów w systemie:

# ps -e
# ps -ew
# ps -e[fF]
# ps -ef -t pts/14
# ps -ef -t tty1
# ps -ejH
# ps -U user

Przykłady opcji w stylu BSD wg stron podręcznika:

# ps ax
# ps axu
# ps axjf
# ps axms
# ps axZ

Można użyć komendy ps do uzyskania wskazanych parametrów procesów, łącznie z własnym opisem i określeniem wielkosci pola, na którym będą zapisywane:

# ps -eo pid:10,tid,class,rtprio,ni,pri,psr:5,pcpu:5,stat:5,wchan:24,comm
# ps -eo uid=user_id,pid=process_id,comm=command_name

Jeśli są uruchomione/wstrzymane jakieś procesy, to można nimi zarządzać poprzez komendy jobs, fg, bg.

Jaki sens mają parametry guid i sid? Jakim procesom odpowiadają te wartości? Można się o tym przekonać wykonując poniższe komendy i analizując dokładnie wyniki działania komendy ps:

# ls /usr/bin | more &
# vi xxx &
# ps -elf| grep a | more &
# ps -o uid,pid,pgid,sid,stat,cmd

Zob. także Procesy, procesy lekkie, wątki jądra i ich stany.

Procesy – priorytety

Co oznacza parametr PRI? prio=priotytet wg jądra (zob. /proc/PID/sched).

proces/wątek

prio

top/htop

ps -eo pri

ps -eo rtprio

ps -el

nice

migration

0

RT

139

99

-40

kworker

100

0

39

60

-20

bash

120

20

19

80

0

khugepaged

139

39

0

99

19

komenda

prio <100

prio >= 100

top/htop

PRI= RT

PRI= prio - 100

ps -eo pri

PRI= 139 - prio

PRI= 139 - prio

ps -el

PRI= prio - 40

PRI= prio - 40

Wraz z wprowadzeniem jądra 2.6.23 (10/2007) planista O(1) został zastąpiony planistą całkowicie sprawiedliwym (CFS, Completely Fair Scheduler), który przydziela kwanty czasu zmiennej długości temu zadaniu (procesowi), które go najbardziej potrzebuje; zob. https://en.wikipedia.org/wiki/Completely_Fair_Scheduler.

Zadania przydzielane są do klas, w których obowiązuje wspólna polityka przydziału CPU. W klasie fair możemy mieć zadania typu:

  • SCHED_NORMAL (zw. także SCHED_OTHER) – polityka przydziału dla zwykłych zadań

  • SCHED_BATCH – rzadsze wywłaszczanie, zadania wykonują się dłużej, lepsze wykorzystanie pamięci podręcznej procesorów; polityka właściwa dla zadań wsadowych

W klasie idle:

  • SCHED_IDLE – polityka przydziału słabsza, niż dla zadań ‘nice 19’; zadanie jest wykonywane, kiedy praktycznie procesor nie ma innych zadań do wykonania

W klasie real time:

  • SCHED_FIFO

  • SCHED_RR.

Od wersji 3.14 jest także dostępna klasa DEADLINE (zob. https://en.wikipedia.org/wiki/SCHED_DEADLINE).

Do nadawania i zmiany prorytetów służy komenda chrt, a do zmiany pozmiomów uprzejmości – nice|snice.

Przykłady zmiany priorytetów procesów:

# chrt -b -p 0 PID
# chrt -r -p 99 PID
# chrt -r -p 98 PID
# chrt -p  PID
# chrt -b -p 0 PID
# renice +19 PID
# renice -20 PID
# nice -n +19 top -d .5

Zob. Przykłady użycia komendy chrt.

Procesy – zarządzanie

Sygnały to jeden z mechanizmów komunikacji międzyprocesowej używany w systemach linuksowych (ogólnie uniksopodobnych). Sygnały są krótkimi wiadomościami, które można wysyłać do procesu lub grupy procesów. Z każdym sygnałem jest związana jego nazwa i numer (zależne od platformy). Jest to mechanizm zarządzania procesami dostępny w trybie użytkownika. Sygnały informują proces o wystąpieniu określonego zdarzenia i powodują, że proces wykonuje zawartej w kodzie procesu funkcję obsługi danego sygnału.

Pełną listę sygnałów można znaleźć na stronach podrecznika systemowego (man 7 signal) lub wykonując komendę kill -l.

Do zarządzania procesami poprzez sygnały używa się następujących komend: pgrep, pkill, skill, killall.

W celu wyprobowania działania tych komend należy utworzyć zestaw procesów wykorzystując do tego takie skrypty jak create2kill1.sh (w trybie tekstowym) oraz create2kill2.sh (w trybie graficznym).

Po uruchomieniu skryptu (np. create2kill1.sh start) można łatwo sprawdzić, jakie procesy zostały utworzone (create2kill1.sh status) i które są wybierane przy zastosowaniu komend:

# pgrep [-l] proc
# pgrep [-l] procA|B
# pgrep [-l] 111|222
# pgrep [-l] [-f] num
# pgrep [-l] [-f] num=
# pgrep [-l] [-f] 12:26

Uwaga! Jeśli w przykładach pojawia się ciąg znaków postaci hh:mm, to trzeba go zastąpić właściwym czasem utworzenia procesów.)

Stosując odpowiednie wyrażenie regularne można spowodować usunięcie wybranego procesu.

Kilka dalszych przykładów:

# pgrep -f './111procA'

# pgrep [-l] '[12]proc'
# pgrep [-l] '[:digit:]{3}proc'
# pgrep [-l] '[ [:digit:] ]{3}proc'
# pgrep [-l] '[ [:digit:] ]{2}proc'
# pgrep [-l] '^[ [:digit:] ]{2}proc'
# pgrep [-l] '^[ [:digit:] ]{3}proc'

# pgrep -l '2.rocA'
# pgrep -l '2p.rocA'
# pgrep -l '2p.ocA'
# pgrep -l '2.....B'

# pgrep '\./111procA'
# pgrep -f '\./111procA'

# pgrep -f '\.\/111procA'
# pgrep -f '.\/111procA'
# pgrep -f '../111procA'

# pgrep -f './111procA'
# pkill -f './111procA'

# pgrep  '11:42'
# pgrep  -f '11:42'

# pgrep -t pts/0

Zob. także Killing processes that don’t want to die https://lwn.net/Articles/754980/.

Procesy – ograniczenia (ulimit)

System operacyjny pozwala na kontrolę zasobów zużywanych przez poszczególne procesy. Powłoka bash udostępnia komendę ulimit, dzięki której można kontrolować dostęp procesów do zasobów (man bash). Rozróżnia się ograniczenia miękkie i twarde. Użytkownik może modyfikować ograniczenia twarde tylko ``w dół’’, a ograniczenia miękkie ``w dół’’ i ``w górę’’, ale tylko do wielkości wyznaczonej przez ograniczenia sztywne.

Jeśli twarde ograniczenie nie jest ustalone w /etc/security/limits.conf, a ulimit -H -t pokazuje unlimited, to nie można go zmienić z poziomu użytkownika, gdyż trzeba jednocześnie zmienić twarde i miękkie ograniczenie. Jeśli jednak użytkownik określi miękkie ograniczenie, np. ulimit -S -t 1000, to zadziała także komenda ulimit -H -t 1000. Prawidłowa kolejność jest następująca:

# ulimit -a
# ulimit -aH
# ulimit -aS
# ulimit -t 1000
# ulimit -aH|S
# ulimit -St 1100
# ulimit -St 200
# ulimit -St 500
# ulimit -Ht 400
# ulimit -St 200
# ulimit -Ht 300

Ograniczenia H i S muszą być tak modyfikowane, aby nigdy ograniczenie twarde nie przyjmowało wartości mniejszej od ograniczenia miękkiego.

Zob. Przykłady użycia komendy ulimit.

Procesy – przekierowania

Zob.

W celu zaobserwowania przekierowań należy porównać i przeanalizować działania poniższych komend:

# ls -l /etc/hosts /etc/passwdd
ls: cannot access /etc/passwdd: No such file or directory
-rw-r--r-- 1 root root 4068 maj 20 17:43 /etc/hosts

# ls -l /etc/hosts /etc/passwdd  > ls.lst
ls: cannot access /etc/passwdd: No such file or directory

# ls -l /etc/hosts /etc/passwdd  1> ls.lst
ls: cannot access /etc/passwdd: No such file or directory

# ls -l /etc/hosts /etc/passwdd  2> ls.lst
-rw-r--r-- 1 root root 4068 maj 20 17:43 /etc/hosts

# ls -l /etc/hosts /etc/passwdd  >& ls.lst

Jak się ma zawartość pliku ls.lst do komunikatów wyświetlanych na konsoli?

Uwaga! Przy wykonywaniu poniższych komend trzeba pamiętać, żeby przed wykonaniem kolejnej usuwać pliki ls.lst i ls.err.

# ls -l /etc/hosts /etc/passwdd  1> ls.lst  2>ls.err
# cat ls.err

# ls -l /etc/hosts /etc/passwdd  1> ls.lst  2>&1
# cat ls.lst
ls: cannot access /etc/passwdd: No such file or directory
-rw-r--r-- 1 root root 1910 Dec 10 19:26 /etc/hosts

# ls -l /etc/hosts /etc/passwdd 2>&1  1> ls.lst
ls: cannot access /etc/passwdd: No such file or directory

Co zawierają pliki ls.lst i ls.err? Dlaczego w ostatnim przykładzie błędy są kierowane na terminal?

Wielokrotna zmiana przekierowania:

# ls -l /etc/hosts /etc/passwdd 1>ls1.lst  1>ls2.lst

Jakiej długości są oba pliki? W jakiej kolejności wyprowadzane są komunikaty?

Poniższe komendy są równoważne

# ls -l /etc/hosts /etc/passwdd  1>ls.lst 2>&1
# ls -l /etc/hosts /etc/passwdd  2>&1 1>ls.lst 2>&1
# cat ls.lst
ls: cannot access /etc/passwdd: No such file or directory
-rw-r--r-- 1 root root 2073 kwi  4 10:40 /etc/hosts

Poniższe także, ale dają inny wynik

# ls -l /etc/hosts /etc/passwdd  2>&1 2>ls.lst 1>ls.lst
# ls -l /etc/hosts /etc/passwdd  2>ls.lst 1>ls.lst
# cat ls.lst
-rw-r--r-- 1 root root 2073 kwi  4 10:40 /etc/hosts
rectory

Z porównania wynika, że najpierw wyprowadzana jest zawartość bufora związanego z deskryptorem 2, a dopiero później – z deskryptorem 1.

Korzystanie z niestandardowych deskryptorów plików:

  • Jak utworzyć plik o zerowej długości lub wyzerować już istniejący plik?

    # : > hosts
    
  • Jak powiązać deskryptor pliku z plikiem?

    # cp /etc/hosts hosts
    # exec 10<hosts
    
  • Ile razy można wykonać komendę cat <&10?

  • Dane z deskryptora 10 można czytać wiersz po wierszu:

    # exec 10<hosts
    # read  line <&10
    # echo $line
    
    # read  line <&10
    # echo $line
    
  • W każdej chwili można deskryptor zamknąć:

    exec 10>&-
    read  line <&10
    
  • Porównać komendę cat /etc/hosts |less z komendami

    # 0</etc/hosts less
    # </etc/hosts less
    

Znaczenie symboli &-, <&-, 2>&-:

  • zamykanie deskryptora pliku n do odczytu: n<&-

  • zamykanie STDIN: 0<&-, <&-

  • zamykanie deskryptora n pliku do zapisu: n>&-

  • zamykanie standardowego wyjścia: 1>&-, >&-

W jednym terminalu mamy sesję basha o numerze np. 4717 (echo $$). W drugim terminalu można obserwować pliki związane z tym procesem przy użyciu komendy: lsof -a -p 4717 -d0,1,2,3,10 (komendę lsof trzeba wywoływać jako użytkownik ‘root’!).

COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
bash    4717 jkob    0u   CHR 136,13      0t0   16 /dev/pts/13
bash    4717 jkob    1u   CHR 136,13      0t0   16 /dev/pts/13
bash    4717 jkob    2u   CHR 136,13      0t0   16 /dev/pts/13

Wygodniej jest te obserwacje robić dla komendy ping wywoływanej z różnymi przekierowaniami:

# ping localhost
# lsof -a -p `pgrep ping`  -d0,1,2
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
ping    12543 root    0u   CHR 136,28      0t0   31 /dev/pts/28
ping    12543 root    1u   CHR 136,28      0t0   31 /dev/pts/28
ping    12543 root    2u   CHR 136,28      0t0   31 /dev/pts/28
# ping localhost > ping.out
# lsof -a -p `pgrep ping`  -d0,1,2
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
ping    13259 root    0u   CHR 136,28      0t0     31 /dev/pts/28
ping    13259 root    1w   REG   8,17      810 139202 /root/ping.out
ping    13259 root    2u   CHR 136,28      0t0     31 /dev/pts/28
# ping localhost 1> ping.out  2>ping.err
# lsof -a -p `pgrep ping`  -d0,1,2
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
ping    13474 root    0u   CHR 136,28      0t0     31 /dev/pts/28
ping    13474 root    1w   REG   8,17      601 139202 /root/ping.out
ping    13474 root    2w   REG   8,17        0 173991 /root/ping.err
# ping localhost 1> ping.out  2>&1
# lsof -a -p `pgrep ping`  -d0,1,2
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
ping    13915 root    0u   CHR 136,28      0t0     31 /dev/pts/28
ping    13915 root    1w   REG   8,17      394 139202 /root/ping.out
ping    13915 root    2w   REG   8,17      394 139202 /root/ping.out
# ping localhost 2>&1 1>ping.out
# lsof -a -p `pgrep ping`  -d0,1,2
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
ping    14122 root    0u   CHR 136,28      0t0     31 /dev/pts/28
ping    14122 root    1w   REG   8,17      950 139202 /root/ping.out
ping    14122 root    2u   CHR 136,28      0t0     31 /dev/pts/28

Do obserwacji przekierowań można także wykorzystać komendę xargs.

  • Potok jest połączony ze standardowym wyjściem:

    # ls -la /etc/passwdd /etc/hosts  | xargs -I{} echo '###' {} '###'
    
  • Standardowe wyjście błędów jest kopią wyjścia standardowego:

    # ls -la /etc/passwdd /etc/hosts 2>&1  | xargs -I{} echo '###' {} '###'
    
  • Któryś ze strumieni wyjściowych jest usuwany:

    # ls -la /etc/passwdd /etc/hosts 1>/dev/null | xargs -I{} echo '###' {} '###'
    # ls -la /etc/passwdd /etc/hosts 2>/dev/null | xargs -I{} echo '###' {} '###'
    
  • Manipulacji na deskryptorach można dokonywać w dowolnym miejscu komendy:

    # 2>&1 ls -la /etc/passwdd /etc/hosts       | xargs -I{} echo '###' {} '###'
    #      ls -la /etc/passwdd /etc/hosts 2>&1  | xargs -I{} echo '###' {} '###'
    
  • Potok jest połączony ze standardowym wyjściem i standardowym wyjściem dla błędów:

    # ls -la /etc/passwdd /etc/hosts |& xargs -I{} echo '###' {} '###'
    
  • Żadna wiadomość nie jest przekazywana do procesu xargs:

    # 1>&2 ls -la /etc/passwdd /etc/hosts       | xargs -I{} echo '###' {} '###'
    #      ls -la /etc/passwdd /etc/hosts 1>&2  | xargs -I{} echo '###' {} '###'
    

    W przypadku zastosowania |& sprzęganie strumieni zachodzi inaczej (dlaczego?):

    # ls -la /etc/passwdd /etc/hosts 1>/dev/null |& xargs -I{} echo '###' {} '###'
    # ls -la /etc/passwdd /etc/hosts 2>/dev/null |& xargs -I{} echo '###' {} '###'