UXP1A Unix Programowanie i Architektura

Podobne dokumenty
UXP1A Unix Programowanie i Architektura

Procesy. Systemy Operacyjne 2 laboratorium. Mateusz Hołenko. 9 października 2011

Sygnały. 7. Sygnały (2005/2006)

Poniższe funkcje opisane są w 2 i 3 części pomocy systemowej.

Obsługa sygnałów. Tomasz Borzyszkowski

Obsługa plików Procesy

Instrukcja do laboratorium Systemów Operacyjnych. (semestr drugi)

UXP1A Unix Programowanie i Architektura

Model procesu w systemie Linux. Tomasz Borzyszkowski

Procesy w systemach UNIX i Linux

SYSTEMY OPERACYJNE I laboratorium 3 (Informatyka stacjonarne 2 rok, semestr zimowy)

procesy odrębne dzielone

UXP1A Unix Programowanie i Architektura

UXP1A Unix Programowanie i Architektura

Procesy, pliki, potoki, sygnały - uzupełnienie

Systemy Operacyjne I: Procesy

Zarządzanie procesami

2. Zarządzanie procesami

Uruchamianie programów w systemie Linux, potoki, strumienie, procesy, alias

Wykład 3. Procesy i wątki. Wojciech Kwedlo, Wykład z Systemów Operacyjnych -1- Wydział Informatyki PB

Systemy operacyjne III

Zarządzanie procesami (omawiane zagadnienia)

Laboratorium Procesy w systemach UNIX 3.2 Polecenia związane z procesami

Procesy pojęcia podstawowe. 1.1 Jak kod źródłowy przekształca się w proces

4. Procesy pojęcia podstawowe

Procesy, wątki i zasoby

Laboratorium systemów operacyjnych ćwiczenie nr 3. [ilość modułów: 1] Temat zajęć: Procesy w systemie operacyjnym

Łącza nienazwane(potoki) Łącza nienazwane mogą być używane tylko pomiędzy procesami ze sobą powiązanymi.

4. Procesy pojęcia podstawowe

1. Ustanawianie ograniczeń na użycie zasobów

1.1 Definicja procesu

Systemy Operacyjne 1 Laboratorium 2 Procesy i sygnały w Linuksie (jeden tydzień) dr inż. Arkadiusz Chrobot

UNIX. mgr inż. Marcin Borkowski

SYSTEMY OPERACYJNE: STRUKTURY I FUNKCJE (opracowano na podstawie skryptu PP: Królikowski Z., Sajkowski M. 1992: Użytkowanie systemu operacyjnego UNIX)

Temat zajęć: Obsługa procesów w systemie.

przerwany proces móg l zareagować na określone zdarzenie. Można je traktować jako software owe wersje przerwań sprz etowych.

IdyllaOS. Prosty, alternatywny system operacyjny. Autor: Grzegorz Gliński. Kontakt:

4. Procesy pojęcia podstawowe

Prezentacja systemu RTLinux

Projektowanie oprogramowania systemów PROCESY I ZARZĄDZANIE PROCESAMI

Zakład Systemów Rozproszonych

"Klasyczna" struktura systemu operacyjnego:

Wykład 5 Przerwania i wywołania systemowe. Wojciech Kwedlo, Systemy Operacyjne II -1- Wydział Informatyki PB

POSIX: IEEE Std (Issue 6, 2004 edition)

Utwórz na pulpicie katalog: pierwsza-litera-imienia_nazwisko (np. j_kowalski). W tym katalogu zapisz pliki, które będą tworzone w ramach ćwiczenia

projektowanie systemu

Procesy, zasoby i wątki

Procesy, zasoby i wątki

Pobieranie argumentów wiersza polecenia

Warstwy systemu Windows 2000

Działanie systemu operacyjnego

2. Zarządzanie procesami

Procesy, zasoby i wątki

Podstawy administracji systemu Linux

Zarządzanie Procesami

Sygnał mechanizm asynchronicznego powiadamiania procesów o zdarzeniach zwykle awaryjnych.

Systemy operacyjne. część 1. Artur Gramacki Instytut Informatyki i Elektroniki. Zalecana literatura

Linux: Procesy. Systemy Operacyjne. Mateusz Hołenko. 26 marca 2013

Administracja systemem Linux p. 1

Działanie systemu operacyjnego

2. Zarządzanie procesami

Administracja systemem Linux

Wprowadzenie do systemu Minix

Użytkownicy I. Użytkownik. Głównym celem istnienia użytkowników i grup w systemie jest utrzymanie porządku i separacja uprawnień.

Jądro Powłoka System plików Programy użytkowe

4.2 Sposób korzystania z l acza

7. Szeregowanie procesów w systemie QNX6 Neutrino

Sygnały i ich obsługa

Sieci komputerowe. Wstęp do systemu Linux/UNIX, część I. Ewa Burnecka / Janusz Szwabiński. ewa@ift.uni.wroc.pl / szwabin@ift.uni.wroc.

Administracja serwerami

Komputery przemysłowe i systemy wbudowane

Proces instalacji systemu operacyjnego Linux Red Hat 7.3 (1)

1. Timery i zdarzenia

Systemy operacyjne. Systemy operacyjne. Systemy operacyjne. Program wykładów. Strona WWW przedmiotu: Program ćwiczeń projektowych

Wykład 1

Wykład 3: Implementacja programów wbudowanych

Krótki kurs programowania współbieżnego

Działanie systemu operacyjnego

Uniwersytet w Białymstoku Wydział Ekonomiczno-Informatyczny w Wilnie SYLLABUS na rok akademicki 2009/2010

Przegląd współczesnych systemów operacyjnych

Działanie systemu operacyjnego

Jądro systemu operacyjnego

SYSTEMY OPERACYJNE WYKLAD 6 - wątki

Egzamin pisemny z przedmiotu: Systemy operacyjne Semestr I

9. Procesy, urządzenia i system plików w systemie Linux

Wprowadzenie do systemu operacyjnego Linux zarzdzanie procesami, cz. 2

SYSTEMY CZASU RZECZYWISTEGO - VxWorks

Zarządzanie procesami i wątkami

1. Tworzenie nowego projektu.

Systemy operacyjne. Instrukcja laboratoryjna. Ćwiczenie 1: Polecenia systemu UNIX/LINUX. Opracował: dr inż. Piotr Szpryngier

Narzędzia zarzadzania i monitorowania w systemach Linux

Budowa systemów komputerowych

Informacje o procesach czyli polecenie "ps".

WIELODOSTĘPNE SYSTEMY OPERACYJNE 1 (SO1)

Powłoka I. Popularne implementacje. W stylu sh (powłoki zdefiniowanej w POSIX) W stylu csh. bash (najpopularniejsza) zsh ksh mksh.

1. Etapy rozwoju systemów komputerowych

Wątki, sygnały i szeregowanie w systemach UNIX, Linux

Instytut Teleinformatyki

Procesy. 5. Procesy (2005/2006)

Programowanie współbieżne Wykład 2. Iwona Kochańska

Transkrypt:

UXP1A Unix Programowanie i Architektura zima 219 Grzegorz Blinowski Instytut Informatyki Politechniki Warszawskiej

Regulamin, itp. Zasady ogólne: Tryb zaliczenia oceny są wystawione najpóźniej ostatniego dnia zajęć (przed rozpoczęciem sesji letniej), 5 p. Projekt, 5 p. kolokwia, 5 p. do zaliczenia przedmiotu Projekt i kolokwia niezbędne do zaliczenia - min. 25 p. za kolokwia, min. 25 p. za projekt nie przewiduje się poprawkowego kolokwium poprawka indywidualne rozmowy Kolokwium 1 godz. lekcyjna, bez notatek Projekt: Projekt rusza po c.a. 1 mies. wykładów Zespoły 4-o osobowe, propozycja własnych projektów - bez sztampowych rozwiązań ujemne punkty za znaczne opóźnienie Projekt wstępny - na papierze i projekt zasadniczy: demo + obszerna dokumentacja Szczegółowe wymagania podane przy rozdawaniu zadań

Regulamin itp. Inne Wolne czwartki: 1/11; 27/12 Nie będzie zajęć w dn. 8 /11i 15/11 odbeda się dodatkowe zajęcia w innym terminie Kolokiwum I po omówieniu mechanizmów IPC (~ 29.11) Kolokiwum II po omówieniu całości materiału (~ 17.1/19) Oceny, wpisy, poprawa 24 lub 25 1/219 Projekt: start prawdopodobnie 29.11, zaliczenie do 22.1 Wymagania Systemy operacyjne Dobra znajomość języka C Materiały dostępne na stronie http://www.ii.pw.edu.pl/~gjb Kontakt: g.blinowski@ii.pw.edu.pl, tel PW: 222347184; konsultacje wt. 1:-12:

Literatura W. Richard Stevens, Advanced Programming in the UNIX Environment Uresh Vahalia, Jadro systemu UNIX, WNT; 21 Berny Goodhear, James Cox, Sekrety magicznego ogrodu UNIX System V Wersja 4 od środka (podręcznik), WNT 21 Marc Rochkind, Programowanie w systemie Unix dla zawansowanych, WNT (wyd. 2; 25) David R. Butenhof, Programming with Posix Threads, Addison-Wesley, 1997 Daniel P. Bovet, Marco Cesati, LINUX kernel, Wydawnictwo RM (O Reilly) 21 M. Bach, Budowa systemu operacyjnego Unix, WNT 1996

Plan wykładów Historia, Standardy Procesy Sygnały Pliki - podstawy Komunikacja IPC (potoki, FIFO, SYSV IPC) Kolokwium nr 1 Pliki cd, zajmowanie plików i rekordów VFS; systemy plików: UFS, Procfs/specfs, NFS (i RPC) VM Wątki XTI (?) boot / init Kolokwium nr 2

Historia 1965-1969: GE&MIT&Bell Labs - MULTICS 1969: Ken Thompson, Dennis Ritchie (Bell Labs): gra "Space Travel", komputer GE-645 1969: PDP-7 (Bell): środowisko systemu plików, obsługa procesow, 2 użytkowników -> PDP-11 UNICS -> UNIX Brian Kernighan; pierwszy użytkownik - wydz. patentowy Bell Labs. 1971: UNIX First Edition 1972: język B; 1973 - język C (Thomson & Ritchie) 1974 - artykuł o Unix-ie w Comm. of the ACM

PDP-7, PDP-11 Architektura: 18 bit RAM: 4 Kw - słów 18b (9KB) RAM maks: 64 Kw (144 KB) Cykl zegara 1.75 us (,571 MHz) Peryferia: klawiatura/drukarka, taśma papierowa, taśma magentyczna Koszt: ok 72 K USD

Historia c.d.

Historia c.a. 1975 -> Edycja 6 - V6 - pierwsza edycja używana poza Bell Labs 1976: Ritchie - stdio 1975-76 pierwsza wersja przeniesiona na inną maszynę niż PDP 1979 - edycja v7 (kompilator C, sh) 1978 - BSD (bazuje na v6) - Bill Joy, komputery VAX11 (32 bit); pierwsza implementacja TCP/IP w BSD (198) Linia "komercyjna": Unix System III, Unix System V AT&T; SVR4 (1989)

(Wikimedia Commons)

Główne innowacje BSD: TCP/IP Sockets API Job control Symlinks System plików UFS Multi-group (przynależność do wielu grup) System V Biblioteki.so TLI, STREAMS IPC (pamięć dzielona, semafory, kolejki komunikatów) SunOS V-node Funkcja mmap() NFS, RPC, XDR

Standardy i organizacje Lata 8-te: wiele wersji na licencji AT&T (od 1983 podział Bell System) Konsorcjum X/Open 1984 199: OSF/1 BSD/Mach; Unix International (AT&T) 1993: COSE, X/Open Obecnie znak handlowy UNIX należy do The Open Group

Standardy SVID System V Interface Definition (AT&T) SUS - Single Unix Specification 1988... POSIX (IEEE) 199+: Spec 117 1997: SUS v2 (Open Group) 21: POSIX:21 SUS v3 (3+ stron) 24: POSIX:24 28: POSIX:28

Standardy Unix System V release 4 (SVID) AT&T, Unix International, Novel X/Open XPG3 (m.in. IPC, X-windows, lokalizacja programów, programy użytkowe, język C) POSIX (wybrane): IEEE P13.1 API (interfejs miedzy systemem operacyjnym a programami) IEEE P13.2 Interpreter poleceń i programy użytkowe IEEE P13.3 Testy zgodności IEEE P13.4a Wątki

(Wikimedia Commons)

Cechy Przenośność - źródła C + znikomy % kodu asamblera Wielozadaniowy i wielodostępny Wiele procesów każdy ma złudzenie posiadania maszyny na własność Równoczesna praca wielu użytkowników Pamięć wirtualna : procesy mogą alokować więcej pamięci niż jest w systemie, mapa pamięci procesu może być "stała" i obejmować całą przestrzeń adresową (4 GB w modelu 32b, 48b adresu w modelu 64b) Wirtualny i rozproszony system plików Wirtualny - w jednym drzewie wiele typów systemów plików Rozproszony - obejmuje wiele maszyn w sieci

System procesów

Procesy- zagadnienia Cykl życia: tworzenie, wykonanie, zakończenie Tryb wykonania: user, kernel Wejście do kernel: syscall, przerwanie, wyjątek Szeregowanie: w jaki sposób proces jest wybierany z listy gotowych procesów, jak lista ta jest zarządzana i sortowana Przełączanie / wywłaszczanie (contex switching) Wykorzystanie pamięci (we współpracy z pod-systemem VM) Wykorzystanie systemu plików (we współpracy z podsystemem VFS) Obsługa wyjątków (sygnały) Timing statystyki, profilowanie, itp.

Diagram stanów procesu SONPROC syscal intr., fault exit() SZOMB SONPROC kernel preempt SRUN sleep schedule SSLEEP wakeup SRUN ten sam stan SIDL (idle) fork()

Diagram stanów procesu (stary)

Diagram stanów procesu - Linux TASK_RUNNING w trakcie wykonania lub gotowy INTERRUPTIBLE lub UNINTERRUPTIBLE odp. SSLEEP TASK_STOPPED (nie pokazany SIGTSTP i inne)

Deskryptor procesu Proces opisany poprzez swój deskryptor Deskr. częściowo zależny od architektury sprzętu Klasyczny podział deskryptora na 2 części: proc - /usr/include/sys/proc.h u - u-area (u-obszar) - /usr/include/sys/user.h Powiązania deskryptorów z innymi strukturami: Struct pid hierarchia procesów (także orphaned flag, odp. hash table, itp) VFS: ufschunk, file, vnode VM: as (address space), seg (segments)

struct proc rejestry procesora: rejestry uniwersalne odkładane na stosie kernelowym procesu w momencie wejścia w tryb jądra(!); rej. kontekstu, wskażniki stosów user i kernel stan procesu (SRUN, SIDL, SZOMB, SONPROC, ) PID, PPID, zdarzenie, na które oczekuje proces pamięć, mapowanie pam. wirt informacje organizacyjne związane z listą procesów i kolejkami schedulara: priorytet, wartość nice, statystyki schedulera proces group wskażnik na u-area limity inf. związane z obsługą sygnałów: maski liczniki czasu inf. związane z obługą select()

struct u (user) katalog aktualny root fs tablica otwartych plików terminal sterujący pole zwrotu f-kcji systemowej liczniki czasu i inne dane statystyczne inf. związane z debugowaniem i core dump-em

Deskryptor procesu w Linux Struktura task: struct task_struct <linux/sched.h> ok 2 KB przydzielany dynamicznie w kernelu <=2.4 dostępny na końcu segmentu stosu jądra (x86) obecnie na stosie jadra zlokalizowany thread_struct powiazany z task_struct

Hierarchia procesów, PID, PPID Drzewiasta hierarchia procesów Dziedziczenie procesów osieroconych przez proces init (ppid==1) Powstawanie procesów zombie deskryptor procesu, którego statusu nie odebrał (jeszcze) rodzic specjalne procesy systemowe: : swapper. scheduler 1: init 2,3,4: pagedaemon, pageout, vmdaemon, fsflush, update Praktyczne znaczenie PID: identyfikacja, ustalenie hierarchii, zapisanie do pliku w celu wysłania sygnału

Polecenie ps ogg% ps -axl UID PID PPID CPU PRI NI VSZ RSS WCHAN STAT TT -18 sched 1 1 456 DLs?? :1.17 Is?? :.58 /sbin/init -- 2 1-18 12 psleep DL?? :.7 (pagedaemon) 3 28 12 psleep DL?? :. (vmdaemon) 4 28 12 update DL?? 62:25.89 27 1 4 18 2 8 pause Is?? :.1 adjkerntz -i 73 1 2 196 448 select Ss?? 2:2.57 syslogd -s 1 1 2 196 472 select Is?? :2.62 inetd 12 1 1 18 332 448 pause Is?? 7:44.83 cron 11 1 on port 25 (sendmail) 2 62 78 select Ss?? :42.97 sendmail: accepting connections 16 wait TIME COMMAND (swapper) (update)

Polecenie ps ogg% ps -axl UID PID PPID CPU PRI NI VSZ RSS WCHAN 167 1 2 2 12152 167 12154 167 1216 STAT 468 64 accept Is 28-2 28 167 1 28 12162 167 1 28 12164 167 2 18841 167 22953 TT TIME COMMAND?? 6:27.12 /usr/local/bin/sshd Z?? :. (sshd) - Z?? :. (sshd) - Z?? :. (sshd) - Z?? :. (sshd) 28 - Z?? :. (sshd) 1 2 836 14 select S?? :2.3 /usr/local/bin/sshd 167 28 Z?? :. 1 18843 18841 18 452 324 pause Ss p :.23 -csh (csh) 1 1917 18843 1 28 636 272 - R+ p :. ps -axl - (sshd) 14142 1 3 176 524 ttyin Is+ v :.9 /usr/libexec/getty Pc ttyv 2315 1 3 176 596 ttyin Is+ v1 :.2 /usr/libexec/getty Pc ttyv1 1 19292 1 3 452 324 ttyin Is+ v2 :.26 -csh (csh) 172 1 3 176 516 ttyin Is+ v3 :.2 /usr/libexec/getty Pc ttyv3 173 1 3 176 516 ttyin Is+ v4 :.2 /usr/libexec/getty Pc ttyv4

API #include <sys/types.h> #include <unistd.h> pid_t getpid(void); pid_t getppid(void);

Mapa pamięci procesu

BSS a Data int a; int b_data=1; int c_bss=; int foo(void) { static foo_a_static; static foo_c_static=1; int foo_dynamic; } return ; $ nm bss_data.o 4 4 4 C D B T b d a b_data c_bss foo foo_a_static. foo_c_static.2 D/d data (global/local) zainicjowane B/b BSS (global/local) niezainicjowane, bez jawnej alokacji T- Text (kod) C Common trafi do BSS, różnica tylko na poziomie plików.o (common wiele wystąpień tej samej niezainicjowanej zmiennej w plikach.o tj. przed konsolidacją (kwestie kompatybliności wstecznej))

Mapa pamięci procesu 2^32 lub 2^4-44 (1-16 TB w adresowaniu 64-o bitowym) Stosy: User stack Kernel stack (pusty, jeśli w trybie user) Syscall: wywołanie funkcji bibliotecznej w trybie user, samo wejście do trybu jądra: uprzywilejowana instrukcja powodująca wyjątek Stos jądra używany normalnie do przechowywania rekordów aktywacji, zmiennych lokalnych itd. Podczas wykonywania kolejnych funkcji w trybie jądra Context switch: na stosie jądra odłożone rejestry itp, co pozwala na powrót przy ponownej aktywacji procesu

Adresowanie 32/64b Model ILP : Int(eger) Long Pointer Klasyczny model: ILP32, 4 GB wirtualnie Przejście na 64b związane nie tylko z systemem ale i z systemem typów w C: LP64: 4/8/8 ILP64: 8/8/8 LLP64: 4/4/8 ILP64 problem z kompatybilnością wstecz LP64: najlepszy kompromis, standard LLP64: bez problemów z kompatybilnością Zob: http://www.unix.org/whitepapers/64bit.html

Użytkownicy i grupy UID: liczba (uid_t) UID - nazwa - mapowanie przez /etc/passwd lub NIS/NIS+ API: #include <sys/types.h> #include <pwd.h> struct passwd *getpwnam(const char *login); struct passwd *getpwuid(uid_t uid); struct passwd *getpwent(void); /* seq read */ int setpwent(void); /* rewind */ void endpwent(void); /* close */

Użytkownicy i grupy root:x::::/root:/bin/bash root:$1$xxxj:13726:::::: bin:x:1:1:bin:/bin: bin:*:9797:::::: daemon:x:2:2:daemon:/sbin: daemon:*:9797:::::: adm:x:3:4:adm:/var/log: adm:*:9797:::::: lp:x:4:7:lp:/var/spool/lpd: lp:*:9797:::::: mail:x:8:12:mail:/: mail:*:9797:::::: news:x:9:13:news:/usr/lib/news: news:*:9797:::::: mysql:x:27:27:mysql:/var/lib/mysql:/bin/bash mysql:*:9797:::::: pop:x:9:9:pop:/: pop:*:9797:::::: nobody:x:99:99:nobody:/: nobody:*:9797:::::: backup:x:3116:1:,,,:/home/backup:/bin/bash backup:$1$xxx/:13231::9999 ulam:x:3113:98:,,,:/home/ulam:/bin/bash ulam:$1xxx:13231::99999:7 tadek:x:312:1:,,,:/home/tadek:/bin/bash tadek:$xxxy1:14532::99999:

Użytkownicy i grupy (API) struct passwd { char *pw_name; /* user name */ char *pw_passwd; /* encrypted password */ int pw_uid; /* user uid */ int pw_gid; /* user gid */ time_t pw_change; /* password change time */ char *pw_class; /* user access class */ char *pw_gecos; /* Honeywell login info */ char *pw_dir; /* home directory */ char *pw_shell; /* default shell */ time_t pw_expire; /* account expiration */ };

Grupy użytkowników Grupa: GID, nazwa, lista użytkowników, hasło Styl BSD użytkownik może należeć do wielu grup na raz wg. tych przynależności ustalane są prawa dostepu do plików i innych zasobów lista akt. grup inicjowana przez roota w momencie logowania się użytkownika do systemu Styl SV proces należy do jednej grupy polecenie/funkcja newgrup() zmiana grupy

/etc/group /etc/group: daemon:*:1:daemon kmem:*:2:root sys:*:3:root tty:*:4:root operator:*:5:root mail:*:6: bin:*:7: news:*:8: man:*:9: games:*:13: staff:*:2:root,gjb guest:*:31:root,guest uucp:*:66:uucp

API grup #include <sys/types.h> #include <grp.h> struct group * getgrnam(const char *name); struct group * getgrgid(gid_t gid); struct group * getgrent(void); int setgrent(void); void endgrent(void);

Real, effective, saved UID/GID Real user / group ID: identyfikacja, rozliczenia (RUID, RGID) Effective user / group ID: uprawnienia (EUID, EGID) Potrzeba zmianu UID dla root (przy logowaniu użytkownika) Potrzeba zmiany praw na innego użytkownika (typowo innego niż root i powrotu do oryginalnych praw) - trzeba zachować szczelny mechanizm uprawnień Wprowadzono Saved user / group ID

Z(a)miana RUID, EUID (RGID, EGID) API setuid( uid_t uid ); setgid ( gid_t gid ); Jeśli root to ustawia RUID, EUID, SVUID (tylko root ustawia RUID) Jeśli nie root oraz uid==ruid uid==svuid ustaw: euid na uid Jesli nie spełnione powyższe to błąd EUID może być ustawione przez exec() SVUID początkowo takie jak EUID

fork(), wait(), exec()

Tworzenie procesów Życie procesu może być rozpatrywane z punktu widzenia jądra systemu oraz z punktu widzenia programisty: uruchomienie programu poprzez wywołanie exec...(), inicjalizację w crt i zakończenie procesu Przekazywanie argumentów przez funkcje exec (różne odmiany funkcji exec() ): main(int argc, char *argv[], char *envp[]) argv[] - nazwa programu rozmiar argv - 512 124 B typowo (stosowanie programu xargs) envp środowisko extern char **environ, getenv( char *par)

Funkcja systemowa fork() fork() - Zwraca: dla potomka, > czyli PID potomka dla proc. rodzica, < w wypadku błędu (za dużo procesów) if ( (childpid = fork()) == ) { /* proces potomny */ exec(...); } else { /* proces macierzysty */ } Cele: Tworzenie nowego procesu Tworzenie demona: fork, exec, exit, fork, exec, exit Tworzenie farmy procesów serwisowych Tworzenie nadzorcy i procesu roboczego (demona) Shell wykonywanie poleceń, przetwarzanie w tle, przetwarzanie potokowe

fork() Duplikacja procesu: Nowy Deskryptor, Nowe segmenty pamięci (stos, sterta, dane) dla potomka takie same po wyjściu z fork() ale nie te sam! Pozostaje b.z.: text Deskryptor: Zostaje częściowo skopiowany, Zmienia się: PID, PPID, Dziedziczone: RUID, EUID, tablica otwartych plików, akt. katalog, umask, ustawienia dotyczące sygnałów

wait() <sys/wait.h> <sys/time.h> <sys/resource.h> int wait( int *status); Oczekuje na zakończenie procesu potomnego (którego kolwiek), funkcja powolna (może być przerwana sygnałem) zwraca 1 jeśli nie było potomka zawiesza się gdy jest potomek, czeka na jego zakończenie gdy potomek wykona jawny lub niejawny exit() wait() się odblokowuje Zombie nie było wait() u rodzica exit() generuje SIGCLD (domyślnie nie ma reakcji) ustawienie konieczny signal( SIGCLD, SIG_IGN) powoduje, że wait() nie jest

Status zwracany przez wait() Status związany z przyczyna zakończenia procesu oraz argumentem dla exit() (return) Arg dla exit() x x c:x8 nr-sygn nr-sygn 8 bit x7f 8 bit Zakończenie przez exit() Sygnał zakończyl potomka: Jeśli core to ustawiony Najstarszy bit mlodszego bajtu Proces zatrzymany nie zakończony

Odmiany wait() int wait3(union wait *status, int options, struct rusage *rusage) status jak dla wait() options WNOHANG zwraca: jeśli nie blok i nic się nie stało, -1 błąd, PID pid_t waitpid(pid_t pid, int *stat_loc, int options); pid == -1 - dowolny proces pid > - czekamy na konkretnego potomka o danym pid pid < -1 czekamy na potomka z danego pgrp = abs(pid) options: WCONTINUED, WNOHANG, WNOWAIT, WUNTRACED

execve() Ładuje i rozpoczyna wykonanie nowego programu do istniejącego procesu Wraca tylko w przypadku błędu Deskryptor procesu po wywołaniu execve() nadpisanie wybranych pól: dane, stos, sterta, text, rejestry, statystyki, liczniki czasu Zachowanie b/z innych: PID, PPID, PGRP, grupy, tablica plików, aktualny katalog, terminal sterujący, rusage, root fs, umask, maska sygnałów (ale nie funkcje obsługi sygnałów! (dlaczego?)) Typowe sytuację błędne: [EACCES] nie ma prawa dostępu do pliku programu, lub brak +x, lub zły typ pliku [ENOENT] brak pliku [ENOEXEC] nieznany lub zły format pliku programu [ENOTDIR] katalog w ścieżce nie jest katalogiem [ETXTBSY] plik programu otwarty do zapisu

Rodzina funkcji exec() #include <unistd.h> extern char **environ; int execl(const char *path, const char *arg,... /*, (char *) */); int execle(const char *path, const char *arg,... /*, (char *), char *const envp[] */); int execlp(const char *file, const char *arg,... /*, (char *) */); int execv(const char *path, char *const argv[]); int execve(const char *path, char *const argv[], char *const envp[]); int execvp(const char *file, char *const argv[]); int execvp(const char *file, const char *search_path, char *const argv[]); Pierwotna funkcja to execve() Funkcje exec..p() - uwzględnienie zmiennej środowiskowej PATH pod warunkiem, że path nie zawiera /; jeśli PATH nie ustawione to przyjmuje się.:/bin:/usr/bin Specjalne traktowanie plików z magiczną sekwencją #!shell Może ustawić EUID, EGID (set user/group id) Uwaga na relację path/file z arg!

Środowisko (environment) gjb@skinner:~$ env MANPATH=/usr/local/man:/usr/man:/usr/lib/java/man TERM=xterm SHELL=/bin/bash SSH_CLIENT=172.22.13.92 622 22 QTDIR=/usr/lib/qt SSH_TTY=/dev/pts/ USER=gjb MAIL=/var/mail/gjb PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/lib/java/bin:/usr/li b/java/jre /bin:/usr/lib/qt/bin:. LC_COLLATE=C PWD=/home/gjb LANG=en_US HOME=/home/gjb gjb@skinner:~$

Środowisko (environment) #include <unistd.h> extern char **environ; char *getenv(const char *name); int putenv(char *string); int setenv(const char *name, const char *value, int overwrite); Przechowywany jest wskaźnik (string nie jest kopiowany) Konwencja nazwa=wartość nie jest narzucona Ostatni element tablicy environ ma wartość NULL

Sygnały Sygnał informacja binarna o zajściu zdarzenia dostarczane przez jądro do procesu. Sygnał określony jest przez jego numer (typ/kod sygnału SIG ) UWAGA nie mylić sygnałów z przerwaniami! Pojęcia: procedura obsługi, obsługa, instalacja proc. obsługi, blokowanie Dostarczanie: "Synchroniczne" związane z akcją procesu SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP, SIGXCPU, SIGEMT, "Asynchroniczne" pozostałe, np: SIGINT, SIGQUIT, SIGKILL, SIGPIPE, SIGALRM, SIGTERM, SIGCLD, SIGURG, SIGIO, SIGSTOP, SIGTTIO, SIGTTOU

Sygnały Przyczyny wystąpienia sygnałów: Sam proces, wyjątek syg. synchr., n.p. SIGSEGV Inny proces dowolny proces (funkcja kill() lub polecenie kill) lub np. proces potomny (SIGCLD); proces z którym się komunikujemy (SIGPIPE) Urządzenie terminal lub pseudoterminal (połączenie sieciowe) SIGINTR, SIGQUIT, SIGSTOP, SIGTTIO, SIGTTOU Komunikacja (gniazda): SIGIO, SIGURG Liczniki czasu: SIGALRM, SIGPROF Konsekwencje sygnałów: Wywołanie procedury obsługi Przerwanie procesu (zakończenie) Zatrzymanie (wstrzymanie procesu) Zrzucenie pliku core

sygnały lista POSIX.1 Signal Value Action Comment ------------------------------------------------------------------------SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling process SIGINT 2 Term Interrupt from keyboard SIGQUIT 3 Core Quit from keyboard SIGILL 4 Core Illegal Instruction SIGABRT 6 Core Abort signal from abort(3) SIGFPE 8 Core Floating point exception SIGKILL 9 Term Kill signal SIGSEGV 11 Core Invalid memory reference SIGPIPE 13 Term Broken pipe: write to pipe with no readers SIGALRM 14 Term Timer signal from alarm(2) SIGTERM 15 Term Termination signal SIGUSR1 3,1,16 Term User-defined signal 1 SIGUSR2 31,12,17 Term User-defined signal 2 SIGCHLD 2,17,18 Ign Child stopped or terminated SIGCONT 19,18,25 Continue if stopped SIGSTOP 17,19,23 Stop Stop process SIGTSTP 18,2,24 Stop Stop typed at tty SIGTTIN 21,21,26 Stop tty input for background process SIGTTOU 22,22,27 Stop tty output for background process

sygnały - lista Sygnały zdefiniowane w POSIX 13.1-21 Signal Value Action Comment ------------------------------------------------------------------------SIGBUS 1,7,1 Core Bus error (bad memory access) SIGPOLL Term Pollable event (Sys V). Synonym of SIGIO SIGPROF 27,27,29 Term Profiling timer expired SIGSYS 12,-,12 Core Bad argument to routine (SVID) SIGTRAP 5 Core Trace/breakpoint trap SIGURG 16,23,21 Ign Urgent condition on socket (4.2 BSD) SIGVTALRM 26,26,28 Term Virtual alarm clock (4.2 BSD) SIGXCPU 24,24,3 Core CPU time limit exceeded (4.2 BSD) SIGXFSZ 25,25,31 Core File size limit exceeded (4.2 BSD) Inne uwagi SIGTERM może być przechwycony i ignorowany SIGKILL nie może być ignorowany, proces zostaje zakończony SIGPIPE, SIGHUP, SIGINT, SIGQUIT też kończą proces, ale można je ignorować

funkcja systemowa kill() #include <signal.h> int kill(int pid_proc, int sig); pid_proc > - sygnał wysyłany do procesu o zadanym pid pid_proc < -1 - sygnał wysyłany do grupy procesów o gid == abs(pid) pid_proc == -1 - sygnał wysyłany do wszystkich procesów poza root (gdy wysyła root), wszystkich procesów o EUID=euid wysyłającego (gdy wysyła nie-root) jeśli sig == sprawdzana będzie możliwość wysłania sygnału zwraca - jeśli powodzenie (udało się dostarczyć sygnał do co najmniej jednego procesu), -1 w przypadku błędu Uwaga - zachowanie kill dla pid_proc < może być nieco różne dla różnych wersji UNIX-a

Funkcja obsługi sygnału int (*signal(int sig, void (*func)(int)))(int); lub: void (*signal(int sig, void(*function)(int)))(int); Albo: typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); Zwraca wskażnik do funkcji int (int) wywoływanej funkcji zostanie przekazany kod sygnału. SIG_IGN, SIG_DFL stałe oznaczające odpowiednio: ignorowanie sygnału oraz akcję domyślną (pierwotnie ustawioną) Posix mówi używać tylko do ustawienia: SIG_IGN i SIG_DFL

sigaction() int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); Nowsza wersja funkcji signal(), act akcja, oact poprzednia akcja struct sigaction { void(*) (int) sa_handler; // może być SIG_IGN/DFL sigset_t sa_mask ; // maska zablokowanych podczas obsługi int sa_flags ;... } Maska określa sygnały wstrzymane (stosowana też w innych funkcjach) Maska sygn jest częścią deskryptora procesu Uwaga rozróżnienie: sygnał ignorowany, sygnał wstrzymany

Maski sygnałów - sigset int sigemptyset( sigset_t *set ); int sigfillset( sigset_t *set ); int sigaddset( sigset_t *set, int signo ); int sigdelset( sigset_t *set, int signo ); int sigismember( const sigset_t *set, int signo ); int sigprocmask(int how, const sigset_t *set, const sigset_t *oset); sigset_t: maska how: SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK

Oczekiwanie na sygnał int pause(void); int sigsuspend(const sigset_t *mask); int sigpending( sigset_t *set ); pause() - bezterminowe oczekiwanie na (jakiś) sygnał sigsuspend() - atomowo zawiesza się i zmienia maskę; maska ulega zmianie tylko do momentu wystąpienia i obsłużenia sygnału sigpending() - Zwraca aktualnie wstrzymane sygnały

Sygnały niezawodne - przykład sig_handler() {flag=1;}... Sig_handler() {flag=1;}... for (;;) { for (;;) { sigprocmask( ); while (flag == ) while (flag == )sygnał pause(); }... sigsuspend(mask); }

Sygnały niezawodne Wstrzymywanie sygnałów Wstrzymywanie w czasie obsługi (patrz sigaction) Kolejkowanie sygnałów gdy sygnał dostarczony kilka razy zanim obsłużony (nie zawsze implementowane) Kolejność dostarczenia nie jest określona, jednak należy oczekiwać, że sygnały takie jak SIGSEGV, SIGBUS, etc. będą miały wyższy priorytet

grupy procesów Proces jest członkiem grupy procesów Jeżeli PGRP == PID to proces jest liderem grupy procesów Do grup procesów można dostarczać sygnały (tzn. do wszystkich procesów w grupie) #include <unistd.h> int getpgrp(); SYS V int getpgrp(int pid) BSD, pid == to pgrp tego procesu pgrp może być zmieniany: int setpgrp(); SYS V zmień PGRP na PID i zostań liderem int setpgrp(int pid, int pgrp); BSD, pid == proces bieżący, <> i EUID=, pid==pgrp tworzymy nową grupę i zostajemy liderem EUID!=: pgrp można zmienić tylko sobie i potomkowi przed wywł. exec()

grupy procesów Używane przez shell-a do zarządzania grupami poleceń ( potokami poleceń) Pozwalają na kontrolowanie, które programy otrzymują sygnały związane z terminalem Tworzenie grupy procesów - przykład: % cat file.txt grep abc grep v def lp & uruchomione procesy tworzą własną grupę, która zaczyna pracę w tle, ale może zostać przełączona na pierwszy plan, wtedy zacznie otrzymywać sygnały od terminala sterującego Grupa procesów tworzona jest poprzez listę struktur proc w kernelu, lider jest na początku listy Wszystkie grupy związane z terminalem: pierwszoplanowe i drugoplanowe - sesja

grupy procesów sterowanie pracami: bash-3.$ sleep 1 ^Z [1]+ Stopped sleep 1 bash-3.$ bg [1]+ sleep 1 & bash-3.$ fg sleep 1 bash-3.$ bash-3.$ read var & <<< Przykład SIGTTIN [1] 18445 [1]+ Stopped bash-3.$ fg read var abcd efgh read var

Grupy procesów Terminal sterujący Sygnaly: SIGINT - ^c SIGQUIT - ^\ SIGSTP - ^z SIGCONT fg, bg SIGSTOP fg, bg SIGTTIN SIGTTOU Grupa procesów drugoplanowych Grupa procesów pierwszoplanowa

grupy i sesje procesów - c.d. sesja (session) grupa grup procesów sesja typowo związana jest z login-shellem użytkownika i grupuje wszystkie prace (grupy procesów) zarówno pierwszo- jak i drugoplanowe - login session proces może zmieniać przynależność do grupy procesow tylko w obrębie sesji grupa procesów i sesja jest zachowana przy exec...() Terminal sterujący jest związany z sesją (podobnie jak z PG) #include <unistd.h> int setsid(void); // tworzy nową sesję i nową PG; // proces staje się liderem sesji i grupy procesów pid_t getsid(pid_t pid); // pobiera SID dla danego procesu

Grupy procesów Identyfikator grupy terminali Liczba całkowita > IGT == pid procesu przywódcy grupy procesów, ktory otworzył terminal, jest to proces sterujący terminala Proces sterujący terminala to zwykle shell użytkownika, a pozostałe to programy dzialające w tle Terminal sterujący: /dev/tty Shell z sterowaniem pracami (job control) zmienia t_pgrp na bieżącą pracę pierwszoplanową Sygnały wysyłane przez terminal sterujący: INT, QUIT, HUP, IO, CONT, WINCH Pozbywanie sie term ster: BSD: ioctl( fd, TIOCNOTTY,...) SVR: setpgrp dla procesu, kóry nie jest przywódcą grupy

Scheduler - podstawy Scheduler decyduje, który z procesów gotowych do wykonania uruchomić. Wkracza między wywłaszczeniem starego a uruchomieniem nowego procesu. Uwaga: tylko procesy w stanie SRUN znajdują się w kolejkach schedulera, np. proces w stanie SSLEEP nie! Wybierany jest gotowy do wykonania proces (SRUN) o największym priorytecie. Priorytety mogą być dynamicznie zmienne Priorytet zależy od wielu czynnikow...

Scheduler Klasy szeregowania (np SVR4) - w zależności od klasy procesy podlegają różnym regułom szeregowania, jednak typowo stosowana jest klasy timeshared ( z podziałem czasu ), systemy niekomercyjne implementuja zazwyczaj tylko szeregowanie timeshared (TS) Kwant czasu ilość czasu jaką ma procesu zanim procesor zostanie mu odebrany Długość zależy od klasy szereg. i priorytetu, może być krótki, długi, nieskończenie długi Kolejki szeregowania: dla każdego priorytetu utrzymywana jest kolejka szeregowania. SYSV: Flagi związane ze shedulerem runrun i krunrun, odpowiednio: wywłaszcz proces w trybie użytkownika (ściśle tuż przed powrotem); wywłaszcz proces w kernelu (możliwe w określonych fragmentach kernela).

Priorytety i klasy 159 1 99 6 59 priorytet Klasa czasu rzeczywistego (realtime) Stały priorytet, może być zmieniony jawnei przez proces Proces musi dobrowolnie oddać procesor Klasa systemowa (system) Procesy takie jak: pageout, fsflush, itp. Stałe, tj. niezmienne priorytety, procesy zawsze wykonują się w trybie jądra Klasa z podziałem czasu (timeshared) Klasa ze zmiennymi priorytetami i zmiennym kwantem czasu

Przełączenie kontekstu Makro: PREEMPT() Wywoływane w kernel-u w punktach możliwego wywłaszczenia { if (krunrun) preempt() } preempt() { Wylicz nową wartość priorytetu (w zależności od klasy szeregowania bieżącego procesu) Odłóż deskryptor bieżącego procesu do odpowiedniej kolejki schedulera swtch() }

Algorytm schedulera klasy TS Zasada: sprawiedliwy i sprawny przydział czasu procesora Realizowana poprzez dynamicznie zmienny priorytet procesu (-59) oraz zmienny kwant czasu Podstawowe reguły: Priorytet jest obniżany gdy proces zużywa duże ilości czasu procesora (tzw. proces obliczeniowy ) - tj. przekracza swój kwant czasu i musi być wywłaszczony. Proces obliczeniowy otrzyma długi kwant czasu. Priorytet jest podwyższany gdy proces nie zużywa całego wyznaczonego mu kwantu czasu, tj. przechodzi w stan oczekiwania SSLEEP (proces zorientowany na I/O). Proces zorientowany na I/O otrzyma krótki kwant czasu.

Wyliczanie priorytetu Suma: Wartość użytkownika (nice) Wartość dynamiczna wyliczana przez scheduler Dla każdego priorytetu przechowywana jest struktura określająca m.in.: kwant czasu, priorytet po upłynięciu kwantu, priorytet po wyjściu ze stanu sleep, czas pracy z danym priorytetem Po wyjściu ze sleep proces otrzymuje (na chwilę) systemowy priorytet (6-99) w zależności od typu zdarzenia, na które oczekiwał proces gdy był uśpiony (blokada pamięci, blokada i-węzła, blokowe I/O, pipe, mount, terminal, SIGCLD, inny sygnał)

Przełączenie kontekstu swtch() { save(); /* zapisz kontekst procesu */ pswtch(); /* znajdź nowy proces do wykonania */ /* curproc wskazuje obecnie wznowiony proces */ resume(); /* przywróć zachowany kontekst nowegoprocesu */ /* tu kernel wykonuje juz nowy proces */ } pswtch() { Uaktualnij statystyki if ( SZOMB ) { Zwolnij zasoby if ( NOWAIT ) { usuń deskryptor } } else { if (SONPROC ) ustaw stan na SRUN } Znajdź proces w stanie SRUN o najwyzszym priorytecie Usuń go z kolejki schedulera, ustaw jego status na SONPROC Zaktualizuj zmienne schedulera

start systemu, init

start systemu - boot Mikrokod uruchamia bootloader bootloader wczytuje i wykonuje program boot boot potrafi zlokalizować (device, file) kernel, przekazać do niego argumenty, zaladować (odpakować) go i przekazać mu sterowanie mlsetup() - inicjalizacja sprzętu, przełączenie procesora w tryb uprzywilejowany, włączenie pamięci wirtualnej dispinit() - uruchomienie schedulera i przerwań zegarowych inicjalizacja systemu procesów, uruchomienie "szkieletowego" procesu pid== dla zadań inicjalizacji kernela uruchomienie main() kernela: inicjalizacja: stronicowania, IO, alokacji pamięci dla jądra, VFS, IPC, zegarów, inicjalizacja urządzeń, itd., wł. obsługi przerwań VFS_MOUNTROOT dla "/" (specjalna funkcja w VFS) konfiguracja swap uruchomienie /sbin/init (fork, specjalna postać exec()) startuje pageout, fsflush i inne serwisy systemowe, init uruchamia skrypty rc

Runlevel Zmienna kernela określająca rodzaj pracy systemu Wprowadzona w SYSV, dostępna w Linux, nieobecne w BSD (choć symulowane w procesie init) Na danym RL mogą działać tylko procesy o takim samym RL Zmiana RL powoduje zabicie procesów związanych z poprzednim RL i uruchomienie nowych związanych z bieżącym RL Zarządzaniem procesami w związku ze zmianą RL zajmuje się proces init init - uruchamiany przy starcie systemu, pid==1, nadzoruje uruchamianie procesów systemowych, jest przodkiem wszystkich procesów Plik konfguracyjny /etc/inittab demona init(d) określa programy, skrypty związane z danym RL (zob. dalej)

Runlevel RL Linux SysVR4 Solaris Halt shutdown ROM 1 Single single/root-fs single/all-fs 2 Multi Multi Multi/Net 3 Multi/Net Multi/Net Multi/exportfs 4 - Multi/user-def Multi/user-def 5 3+DM Halt,firmware shutdown,pwroff 6 reboot reboot reboot s - ==1, current term==cons single/root-fs DM X Display manager root-fs tylko fs / zamontowane (RO) all-fs wszystkie systemy zamontowane exportfs systemy plików NFS eksportowane ROM interpreter wbudowany w hardware (SPARC)

inittab id:rlevel:action:process is:3:initdefault: p3:s1234:powerfail:/usr/sbin/shutdown -y -i5 -g >/dev/msglog 2<>/dev/msglog ss:s:wait:/sbin/rcs >/dev/msglog 2<>/dev/msglog </dev/console s::wait:/sbin/rc >/dev/msglog 2<>/dev/msglog </dev/console s1:1:respawn:/sbin/rc1 >/dev/msglog 2<>/dev/msglog </dev/console s2:23:wait:/sbin/rc2 >/dev/msglog 2<>/dev/msglog </dev/console s3:3:wait:/sbin/rc3 >/dev/msglog 2<>/dev/msglog </dev/console s5:5:wait:/sbin/rc5 >/dev/msglog 2<>/dev/msglog </dev/console s6:6:wait:/sbin/rc6 >/dev/msglog 2<>/dev/msglog </dev/console fw::wait:/sbin/uadmin 2 >/dev/msglog 2<>/dev/msglog </dev/console of:5:wait:/sbin/uadmin 2 6 >/dev/msglog 2<>/dev/msglog </dev/console rb:6:wait:/sbin/uadmin 2 1 >/dev/msglog 2<>/dev/msglog </dev/console sc:234:respawn:/usr/lib/saf/sac -t 3 co:234:respawn:/usr/lib/saf/ttymon -g -h -p "`uname -n` console login: " -T sun -d /dev/console -l console -m ldterm,ttcompat

inittab akcje w inittab: respawn - urucham jeśli się zakończy wait - uruchom, czekaj na koniec once - uruchom asynchronicznie boot, bootwait - przy starcie (RL bez znaczenia) power, powerwait - jeśli awaria zasilania off - wyślij SIGTERM, 5s, SIGKILL (domyślne zachowanie przy zmianie RL) initdefalt - domyślny RL skrypty rc (/etc/rcn.d): katalog/zestaw skryptów dla wybranych RL (,1,2,3),1: zabicie procesów przykład dla RL==2: S1mountfs, S2syssetup, S69inet, S71rpc, S75cron przykład dla RC==3: S1sshd, S2apache

Procesy typu demon Poces demon (daemon) proces drugo-planowy nie ma terminala nie ma shella zgłoszeniowego Podstawowe usługi oferowane przez demony : wywołanie programu w określonym czasie drukowanie - lpd poczta Inna komunikacja - uucp statystyka śledzenie procesów - sendmail, postfix,... Wiele innych - acct - sar, profiler - crontab, at, batch

Procesy typu demon Uruchamianie przez: init lub skrypty rc Cron - crond (plikicrontab) lub at Bezpośrednio przez użytkownika Podstawowe usługi oferowane przez demony : raz uruchamiany nie umiera i nie jest wznawiany (ale init respawn) aktywowany zdarzeniem Typowo powołuje procesy potomne obsługujące zdarzenia

Procesy typu demon 1. Zamknij deskryptory plików SV BSD #include <sys/param.h> /* _NFILE w <stdio.h>, getdtablesize() */ for (i=; i<nofile; i++) close(i); 2. Zmień katalog roboczy chdir( / ); 3. Wyzeruj maskę trybu dostępu umask(); 4. Przejdź na do pracy drugo-planowej fork() exit() brak & 5. Odłącz się od grupy setpgrp(); /*SV*/ setpgrp(, getpid()); /*BSD*/ 6. Ignoruj sygnały terminala wyniki procesu drugo-planowego na terminal? #ifdef SIGTTOU /* SIGTTIN, SIDTSTP */ signal(sigttou, SIG_IGN); #endif

Procesy typu demon 7. Odłącz się od terminala *SV*/ setpgrp(); if (fork()!= ) setpgrp(); wskaźnik do terminala = NULL <=> proces nie jest przywódcą exit(); /* proces macierzysty*/ /* proces potomny*/ /*BSD*/ if ((fd = open( /dev/tty, O_RDWR)) >= ) { ioctl(fd, TIOCNOTTY, (char*) ); close(fd); } 8. Jeśli tworzymy procesy potomne to zadbajmy o poprawną obsługę ich zakończenia, tj. wait() lub: signal( SIGCLD, SIG_IGN);