UXP1A Unix Programowanie i Architektura

Podobne dokumenty
UXP1A Unix Programowanie i Architektura

UXP1A Unix Programowanie i Architektura

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

Systemy Operacyjne ZAAWANSOWANE OPERACJE WEJŚCIA-WYJŚCIA DLA PLIKÓW

Obsługa plików Procesy

UXP1A Unix Programowanie i Architektura

UXP1A Unix Programowanie i Architektura

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

Programowanie Współbieżne. W Linuxie/Unixie

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

Pliki. Funkcje tworzące pliki i operujące na nich opisane są w części 2 pomocy systemowej. Tworzenie i otwieranie plików:

Obsługa plików. Systemy Operacyjne 2 laboratorium. Mateusz Hołenko. 25 września 2011

Programowanie w systemie UNIX

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

Laboratorium z systemów operacyjnych. System plików - funkcje systemowe. Anna Wojak

Obsługa sygnałów. Tomasz Borzyszkowski

Laboratorium Systemów Operacyjnych. Ćwiczenie 4. Operacje na plikach

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

Procesy w systemach UNIX i Linux

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

Model procesu w systemie Linux. Tomasz Borzyszkowski

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

2. Zarządzanie procesami

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

procesy odrębne dzielone

Wstęp do informatyki Shell podstawy

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

Systemy Operacyjne I: Procesy

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

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

Procesy. S. Samolej: Procesy

"Klasyczna" struktura systemu operacyjnego:

Zarządzanie procesami

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

Działanie systemu operacyjnego

Egzamin pisemny z przedmiotu: Systemy operacyjne Semestr I

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

Linux: System Plików

4.2 Sposób korzystania z l acza

Temat zajęć: Obsługa systemu plików.

Podstawy administracji systemu Linux

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

Wybrane funkcje systemowe Unixa

Kurs systemu Unix wykład wstępny. Kurs systemu Unix 1

4. Komunikacja pomiędzy procesami przez łącza nienazwane i nazwane

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

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

System plików Linuxa. Tomasz Borzyszkowski

Wykład 3: Implementacja programów wbudowanych

Prezentacja systemu RTLinux

Operacje powiązane z systemem:

Zarządzanie procesami (omawiane zagadnienia)

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

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

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

Pobieranie argumentów wiersza polecenia

Systemy operacyjne III

Jądro linuksa. LINUX KERNEL O REILLY Daniel P. Bovet & Marco Cesati

UNIX. mgr inż. Marcin Borkowski

Procesy, wątki i zasoby

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

Warstwy systemu Windows 2000

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

Krótki kurs programowania współbieżnego

Działanie systemu operacyjnego

Łącza nienazwane(potoki)

Zakład Systemów Rozproszonych

4. Procesy pojęcia podstawowe

Administracja systemem Linux p. 1

4. Procesy pojęcia podstawowe

J. Ułasiewicz Łącza nienazwane, nazwane, select 1

Prawa dostępu do plików

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

System operacyjny UNIX system plików. mgr Michał Popławski, WFAiIS

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

Działanie systemu operacyjnego

POSIX: IEEE Std (Issue 6, 2004 edition)

Projektowanie oprogramowania systemów PROCESY I ZARZĄDZANIE PROCESAMI

1.1 Definicja procesu

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

2. Zarządzanie procesami

Zarządzanie Procesami

System plików Linuksa

Działanie systemu operacyjnego

Wstęp do informatyki. stęp do informatyki Polecenia (cz.2)

Systemy Operacyjne I: System plików

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

projektowanie systemu

Szkolenie AGH Linux. Nie bój się konsoli i zdaj kolosa na 5.0!!! Tytuł wcale nie przesadzony ;)

Linux Kernel III. Character devices

Znaki globalne w Linuxie

Linux Kernel. Wprowadzenie

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

Bash - wprowadzenie. Bash - wprowadzenie 1/39

Współczesne systemy komputerowe

Proces instalacji systemu operacyjnego Linux Red Hat 7.3 (1)

Instrukcja do laboratorium Systemów Operacyjnych (semestr drugi)

Temat zajęć: Obsługa łączy komunikacyjnych

1. Tworzenie nowego projektu.

2. System uprawnień w linuxie

Transkrypt:

UXP lato ๒๐๑๗, Grzegorz Blinowski UXP1A Unix Programowanie i Architektura lato 2017 Grzegorz Blinowski Instytut Informatyki Politechniki Warszawskiej

UXP lato ๒๐๑๗, Grzegorz Blinowski Regulamin, itp. Zasady ogólne: Tryb zaliczenia oceny są wystawione najpóźniej ostatniego dnia zajęć (przed rozpoczęciem sesji letniej), 50 p. Projekt, 50 p. kolokwia, 50 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ń

UXP lato ๒๐๑๗, Grzegorz Blinowski Regulamin itp. Inne Wolne czwartki: 13/04 Kolokiwum I po omówieniu mechanizmów IPC (~ 06.04) Kolokiwum II po omówieniu całości materiału (~ 01.06) Oceny, wpisy, poprawa 08.06 Projekt: start prawdopodobnie 06.04, zaliczenie do 01.06 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. 10:00-12:00

UXP lato ๒๐๑๗, Grzegorz Blinowski Literatura W. Richard Stevens, Advanced Programming in the UNIX Environment Uresh Vahalia, Jadro systemu UNIX, WNT; 2001 Berny Goodhear, James Cox, Sekrety magicznego ogrodu UNIX System V Wersja 4 od środka (podręcznik), WNT 2001 Marc Rochkind, Programowanie w systemie Unix dla zawansowanych, WNT (wyd. 2; 2005) David R. Butenhof, Programming with Posix Threads, Addison-Wesley, 1997 Daniel P. Bovet, Marco Cesati, LINUX kernel, Wydawnictwo RM (O Reilly) 2001 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 (0,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 (1980) 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 80-te: wiele wersji na licencji AT&T (od 1983 podział Bell System) Konsorcjum X/Open 1984 1990: 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) 1990+: Spec 1170 1997: SUS v2 (Open Group) 2001: POSIX:2001 SUS v3 (3000+ stron) 2004: POSIX:2004 2008: POSIX:2008

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 P1003.1 API (interfejs miedzy systemem operacyjnym a programami) IEEE P1003.2 Interpreter poleceń i programy użytkowe IEEE P1003.3 Testy zgodności IEEE P1003.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: 0: 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 0 0 0 0-18 0 0 0 sched 0 1 0 0 10 0 456 DLs?? 0:10.17 Is?? 0:00.58 /sbin/init -- 0 2 0 1-18 0 0 12 psleep DL?? 0:00.07 (pagedaemon) 0 3 0 0 28 0 0 12 psleep DL?? 0:00.00 (vmdaemon) 0 4 0 0 28 0 0 12 update DL?? 62:25.89 0 27 1 4 18 0 200 80 pause Is?? 0:00.01 adjkerntz -i 0 73 1 0 2 0 196 448 select Ss?? 2:02.57 syslogd -s 0 100 1 0 2 0 196 472 select Is?? 0:02.62 inetd 0 102 1 1 18 0 332 448 pause Is?? 7:44.83 cron 0 110 1 0 on port 25 (sendmail) 2 0 620 708 select Ss?? 0:42.97 sendmail: accepting connections 160 wait TIME COMMAND (swapper) (update)

Polecenie ps ogg% ps -axl UID PID PPID CPU PRI NI VSZ RSS WCHAN 0 167 1 2 2 0 12152 167 0 0 12154 167 0 12160 STAT 0 468 604 accept Is 28 0 0 0-2 28 0 0 167 1 28 0 0 12162 167 1 28 0 12164 167 2 0 18841 167 0 22953 TT TIME COMMAND?? 6:27.12 /usr/local/bin/sshd Z?? 0:00.00 (sshd) 0 - Z?? 0:00.00 (sshd) 0 0 - Z?? 0:00.00 (sshd) 0 0 0 - Z?? 0:00.00 (sshd) 28 0 0 0 - Z?? 0:00.00 (sshd) 1 2 0 836 1040 select S?? 0:02.03 /usr/local/bin/sshd 167 0 28 0 0 Z?? 0:00.00 100 18843 18841 0 18 0 452 324 pause Ss p0 0:00.23 -csh (csh) 100 19017 18843 1 28 0 636 272 - R+ p0 0:00.00 ps -axl 0 - (sshd) 0 14142 1 0 3 0 176 524 ttyin Is+ v0 0:00.09 /usr/libexec/getty Pc ttyv0 0 2315 1 0 3 0 176 596 ttyin Is+ v1 0:00.02 /usr/libexec/getty Pc ttyv1 100 19292 1 0 3 0 452 324 ttyin Is+ v2 0:00.26 -csh (csh) 0 172 1 0 3 0 176 516 ttyin Is+ v3 0:00.02 /usr/libexec/getty Pc ttyv3 0 173 1 0 3 0 176 516 ttyin Is+ v4 0:00.02 /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=0; int foo(void) { static foo_a_static; static foo_c_static=1; int foo_dynamic; } return 0; $ nm bss_data.o 00000004 00000000 00000000 00000000 00000004 00000004 C D B T b d a b_data c_bss foo foo_a_static.0 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^40-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:0:0::/root:/bin/bash root:$1$xxxj0:13726:0::::: bin:x:1:1:bin:/bin: bin:*:9797:0::::: daemon:x:2:2:daemon:/sbin: daemon:*:9797:0::::: adm:x:3:4:adm:/var/log: adm:*:9797:0::::: lp:x:4:7:lp:/var/spool/lpd: lp:*:9797:0::::: mail:x:8:12:mail:/: mail:*:9797:0::::: news:x:9:13:news:/usr/lib/news: news:*:9797:0::::: mysql:x:27:27:mysql:/var/lib/mysql:/bin/bash mysql:*:9797:0::::: pop:x:90:90:pop:/: pop:*:9797:0::::: nobody:x:99:99:nobody:/: nobody:*:9797:0::::: backup:x:3116:100:,,,:/home/backup:/bin/bash backup:$1$xxx/:13231:0:9999 ulam:x:3113:98:,,,:/home/ulam:/bin/bash ulam:$1xxx0:13231:0:99999:7 tadek:x:3120:100:,,,:/home/tadek:/bin/bash tadek:$xxxy1:14532:0: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:*:20: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 crt0 i zakończenie procesu Przekazywanie argumentów przez funkcje exec (różne odmiany funkcji exec() ): main(int argc, char *argv[], char *envp[]) argv[0] - nazwa programu rozmiar argv - 5120 10240 B typowo (stosowanie programu xargs) envp środowisko extern char **environ, getenv( char *par)

Funkcja systemowa fork() fork() - Zwraca: 0 dla potomka, > 0 czyli PID potomka dla proc. rodzica, < 0 w wypadku błędu (za dużo procesów) if ( (childpid = fork()) == 0 ) { /* 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() 0x00 0x00 c:0x80 nr-sygn nr-sygn 8 bit 0x7f 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: 0 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 > 0 - czekamy na konkretnego potomka o danym pid pid < -1 czekamy na potomka z danego pgrp = abs(pid) options: WCONTINUED, WNOHANG, WNOWAIT, WUNTRACED

execve() Ładuje nowy program 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 *arg0,... /*, (char *)0 */); int execle(const char *path, const char *arg0,... /*, (char *)0, char *const envp[] */); int execlp(const char *file, const char *arg0,... /*, (char *)0 */); 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() Uwzględnienie zmiennej środowiskowej PATH Specjalne traktowanie plików z magiczną sekwencją #!shell Może ustawić EUID, EGID (set user/group id) Uwaga na relację path/file z arg0!

Środowisko (environment) gjb@skinner:~$ env MANPATH=/usr/local/man:/usr/man:/usr/lib/java/man TERM=xterm SHELL=/bin/bash SSH_CLIENT=172.22.103.92 60220 22 QTDIR=/usr/lib/qt SSH_TTY=/dev/pts/0 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 Źródła 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 30,10,16 Term User-defined signal 1 SIGUSR2 31,12,17 Term User-defined signal 2 SIGCHLD 20,17,18 Ign Child stopped or terminated SIGCONT 19,18,25 Continue if stopped SIGSTOP 17,19,23 Stop Stop process SIGTSTP 18,20,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 1003.1-2001 Signal Value Action Comment ------------------------------------------------------------------------SIGBUS 10,7,10 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,30 Core CPU time limit exceeded (4.2 BSD) SIGXFSZ 25,25,31 Core File size limit exceeded (4.2 BSD)

funkcja systemowa kill() #include <signal.h> int kill(int pid_proc, int sig); pid_proc > 0 - 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 == 0 sprawdzana będzie możliwość wysłania sygnału zwraca 0 - jeśli powodzenie (udało się dostarczyć sygnał do co najmniej jednego procesu), -1 w przypadku błędu Uwaga - zachowanie kill dla pid_proc <0 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); 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ą)

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

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

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

sigset int sigpending( sigset_t *set ); Zwraca aktualnie wstrzymane sygnały int sigsuspend( const sigset_t *set ); Zawiesza się i atomowo odblokowuje wskazane sygnały

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 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 == 0 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 == 0 proces bieżący, <> 0 i EUID=0, pid==pgrp tworzymy nową grupę i zostajemy liderem EUID!=0: 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.00$ sleep 10 ^Z [1]+ Stopped sleep 10 bash-3.00$ bg [1]+ sleep 10 & bash-3.00$ fg sleep 10 bash-3.00$ bash-3.00$ read var & <<< Przykład SIGTTIN [1] 18445 [1]+ Stopped bash-3.00$ 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 > 0 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 100 99 60 59 0 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 (0-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 (60-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==0 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ępne 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 0 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 -g0 >/dev/msglog 2<>/dev/msglog ss:s:wait:/sbin/rcs >/dev/msglog 2<>/dev/msglog </dev/console s0:0:wait:/sbin/rc0 >/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:0:wait:/sbin/uadmin 2 0 >/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 300 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 (0,1,2,3) 0,1: zabicie procesów przykład dla RL==2: S01mountfs, S20syssetup, S69inet, S71rpc, S75cron przykład dla RC==3: S10sshd, S20apache

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=0; i<nofile; i++) close(i); 2. Zmień katalog roboczy chdir( / ); 3. Wyzeruj maskę trybu dostępu umask(0); 4. Przejdź na do pracy drugo-planowej fork() exit() brak & 5. Odłącz się od grupy setpgrp(); /*SV*/ setpgrp(0, 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()!= 0) setpgrp(); wskaźnik do terminala = NULL <=> proces nie jest przywódcą exit(0); /* proces macierzysty*/ /* proces potomny*/ /*BSD*/ if ((fd = open( /dev/tty, O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, (char*) 0); close(fd); } 8. Jeśli tworzymy procesy potomne to zadbajmy o poprawną obsługę ich zakończenia, tj. wait() lub: signal( SIGCLD, SIG_IGN);

System plików

System plików - podstawy Drzewo plików Korzeń drzewa: File system root, katalog aktualny current dir Korzeń systemowy, korzeń dla procesu (zwykle takie same) int chroot(const char *path); Typy plików: zwykłe, katalogi (d), sterowniki znakowe (c) i blokowe (b), FIFO (p), sym-link (l), socket (s), inne Nazwa (nazwa nie jest atrybutem): znaki dozwolone wszystkie prócz \0 i / Niezalecane znaki wzorce shella, spacja Atrybuty plików: właściciel, grupa Typ / prawa dostępu: owner (user), group, other; setuid, setgid, sticky Daty-czasy: dostępu, modyfikacji, modyfikacji metryczki

System plików pwd, cd, mkdir, rmdir, ls, cp, mv, rm, chown, chgrp, chmod Linki symboliczne, ln, lchown koncepcja wzorca w shellu: *, [],?, eg: [a-z], [^a-z] - regexp

Atrybuty plików drwxr-xr-x 3 gjb staff 1024 Mar 20 12:00 Prace Znaczenie pól: Oznaczenie typu pliku: -, d, c, b, p, l,... Oznaczenie praw dostępu: rwxrwxrwx Liczba (sztywnych) dowiązań do pliku (wskazań z katalogów) User Group Rozmiar w B Data-czas (3 warianty), typowo ost. modyfikacja Nazwa pliku

Prawa dostępu pliki/katalogi 3 triady: właściciel, grupa, pozostali; znaczenie bitów rwx: r: plik - czytanie; katalog - dostęp do nazw plików w: plik pisanie; katalog tworzenie, usuwanie, zmiana nazwy pliku x: plik wykonanie (pod warunkiem, że właściwy format dla exec()); katalog dostęp do danych i meta-danych pliku (ale nie nazwy!), także dozwolona operacja cd Uwaga: prawa nie są dziedziczone katalog katalog, ani katalog plik (zob. jednak g+x); brak danego prawa oznacza odmowę dostępu; dla katalogu rzadko nie łączymy rx

user@host:/etc$ ls -la ls -la total 1896 drwxr-xr-x 47 root root 4096 2011-08-22 08:00./ drwxr-xr-x 20 root root 4096 2010-07-07 21:21../... drwxr-xr-x 10 root root 4096 2011-10-04 14:43 rc.d/ lrwxrwxrwx 1 root root 10 2008-08-06 09:42 rc0.d -> rc.d/rc0.d/ lrwxrwxrwx 1 root root 10 2008-08-06 09:42 rc1.d -> rc.d/rc1.d/ lrwxrwxrwx 1 root root 10 2008-08-06 09:42 rc2.d -> rc.d/rc2.d/ lrwxrwxrwx 1 root root 10 2008-08-06 09:42 rc3.d -> rc.d/rc3.d/ lrwxrwxrwx 1 root root 10 2008-08-06 09:42 rc4.d -> rc.d/rc4.d/ lrwxrwxrwx 1 root root 10 2008-08-06 09:42 rc5.d -> rc.d/rc5.d/ lrwxrwxrwx 1 root root 10 2008-08-06 09:42 rc6.d -> rc.d/rc6.d/ -rw-r--r-- 1 root root 64 2009-02-02 14:18 resolv.conf lrwxrwxrwx 1 root root 16 2008-08-06 09:42 rmt -> /usr/libexec/rmt* -rw-r--r-- 1 root root 1615 2008-04-20 08:08 rpc drwxr-xr-x 3 root root 4096 2008-05-28 22:17 samba/ -rw-r--r-- 1 root root 3302 2007-04-10 23:56 screenrc -rw-r--r-- 1 root root 73695 2009-02-02 11:55 services

Prawa do katalogów gjb@skinner:~/test$ ls -lr total 4 drwxr-xr-x 3 gjb users 4096 2015-11-05 13:18 a/./a: total 8 drwxr-xr-x 2 gjb users 4096 2015-11-05 13:18 b/ -rw-r--r-- 1 gjb users 1 2015-11-05 13:18 p.txt./a/b: total 0 gjb@skinner:~/test$ chmod ogu-x a gjb@skinner:~/test$ ls -lr total 4 drw-r--r-- 3 gjb users 4096 2015-11-05 13:18 a/ /bin/ls: cannot access./a/b: Permission denied /bin/ls: cannot access./a/p.txt: Permission denied./a: total 0 d?????????????? b/ -?????????????? p.txt /bin/ls: cannot open directory./a/b: Permission denied

Atrybuty plików c.d. sticky bit ("lepki") dawno - program ma pozostać w pamięci (nie być swapowany/pageowany) (tylko historyczne) katalog - prawo +w nie pozwala na usuwanie plików (zastosowanie: /tmp), usuwać może: root, właściciel pliku, właściciel katalogu tylko root może ustawiać s-b Immutable bit (BSD, Linux) - dodatkowy bit, gdy ustawiony pliku nie można usunąć (nawet root), stosowany do chronienia ważnych plików systemowych

Atrybuty plików c.d. prawo G+S (SETGID) dla katalogu: tworzone pliki beda dziedziczyć grupę katalogu, a nie użytkownika gjb@skinner:~$ mkdir test1 gjb@skinner:~$ ls -ld test1 drwxr-xr-x 2 gjb users 4096 2014-03-13 12:38 test1/ gjb@skinner:~$ chmod g+s test1 gjb@skinner:~$ ls -ld test1 drwxr-sr-x 2 gjb users 4096 2014-03-13 12:38 test1/ gjb@skinner:~$ chgrp cvs test1; cd test1 gjb@skinner:~/test1$ touch a; mkdir b gjb@skinner:~/test1$ chmod g-s. ; touch c gjb@skinner:~/test1$ ls -la total 12 drwxr-sr-x 3 gjb cvs 4096 2014-03-13 12:39./ drwx--x--x 24 gjb users 4096 2014-03-13 12:38../ -rw-r--r-- 1 gjb cvs drwxr-sr-x 2 gjb cvs -rw-r--r-- 1 gjb users 0 2014-03-13 12:39 a 4096 2014-03-13 12:39 b/ 0 2014-03-13 12:45 c

API systemu plików chmod, chown, close, creat, dup, dup2, fcntl, link, lseek, open, read, stat, umask, write, unlink, stat(5),

Funkcja open() #include <sys/stat.h> #include <fcntl.h> int open(const char *path, int oflag, /* mode_t mode */...); oflag: O_RDONLY, O_WRONLY, O_RDWR O_NDELAY - obiekty komunikacyjne O_APPEND dopisuj do końca O_CREAT utwórz jeśli nie ma O_TRUNC zmniejsz długość do 0 (nadpisz) O_EXCL razem z O_CREAT utwórz tylko jeśli nie istnieje mode 32 bit, określa zarówno prawa dostępu (niższe bity, jak i typ oraz dodatkowe atrybuty wyższe bity)

mode #define S_IRWXU 00700 /* read, write, execute: owner */ #define S_IRUSR 00400 /* read permission: owner */ #define S_IWUSR 00200 /* write permission: owner */ #define S_IXUSR 00100 /* execute permission: owner */ #define S_IRWXG 00070 /* read, write, execute: group */ #define S_IRGRP 00040 /* read permission: group */ #define S_IWGRP 00020 /* write permission: group */ #define S_IXGRP 00010 /* execute permission: group */ #define S_IRWXO 00007 /* read, write, execute: other */ #define S_IROTH 00004 /* read permission: other */ #define S_IWOTH 00002 /* write permission: other */ #define S_IXOTH 00001 /* execute permission: other */

mode typy, maski #define S_IFMT 0xF000 /* type of file */ #define S_IAMB 0x01FF /* access mode bits */ #define S_IFIFO 0x1000 /* fifo */ #define S_IFCHR 0x2000 /* character special */ #define S_IFDIR 0x4000 /* directory */ #define S_IFBLK 0x6000 /* block special */ #define S_IFREG 0x8000 /* regular */ #define S_IFLNK 0xA000 /* symbolic link */ #define S_IFSOCK 0xC000 /* socket */ #define S_IFDOOR 0xD000 /* door */ #define S_ISUID 0x0800 /* set user id on execution */ #define S_ISGID 0x0400 /* set group id on execution */ #define S_ISVTX 0x0200 /* save swapped text even after use */ #define S_IREAD 00400 /* read permission, owner */ #define S_IWRITE 00200 /* write permission, owner */ #define S_IEXEC 00100 /* execute/search permission, owner */ #define S_ENFMT S_ISGID /* record locking enforcement flag */

mode makra typu #define S_ISFIFO(mode) (((mode)&0xf000) == 0x1000) #define S_ISCHR(mode) (((mode)&0xf000) == 0x2000) #define S_ISDIR(mode) (((mode)&0xf000) == 0x4000) #define S_ISBLK(mode) (((mode)&0xf000) == 0x6000) #define S_ISREG(mode) (((mode)&0xf000) == 0x8000) #define S_ISLNK(mode) (((mode)&0xf000) == 0xa000) #define S_ISSOCK(mode) (((mode)&0xf000) == 0xc000) #define S_ISDOOR(mode) (((mode)&0xf000) == 0xd000)

creat(), dup(), dup2() #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int creat(const char *path, mode_t mode); Zwracany deskryptor O_WRONLY Jeśli istnieje jest skracany do 0 Jest równoważny open(path, O_WRONLY O_CREAT O_TRUNC, mode) #include <unistd.h> int dup(int fd); int dup2(int fd, fd2); Duplikuje wskazany deskryptor, dup2() - nadpisuje fd2 Dup(): zwrócony deksryptor będzie najniższy numerycznie z dostępnych Równoważne fcntl(int fd, F_DUPFD, 0)

read(), write(), lseek() int read(int fd, char *buff, unsigned int nbytes); int write(int fd, char *buff, unsigned int nbytes); Zwraca liczbę odczytanych/zapisanych bajtów, 0/-1 koniec pliku lub brak miejsca na fs long int lseek(int fd, long offset, int whence); off64_t lseek64(int fd, off64_t offset, int whence); whence: 0 SEEK_SET przesuń od początku pliku (suma) 1 SEEK_CUR przesuń od pozycji bieżącej (suma) 2 SEEK_END przesuń od końca pliku (suma uwaga offset może być tu dodatni i ujemny)

stat() #include <sys/types.h> #include <sys/stat.h> int stat(const char *path, struct stat *buf); int lstat(const char *path, struct stat *buf); int fstat(int fildes, struct stat *buf); lstat - działa na sym-linku (a nie na wskazanym pliku) fstat działa na otwartym pliku

struct stat { struct stat ushort st_mode; /* typ i prawa dostępu */ ino_t st_ino; /* Inode number */ dev_t st_dev; /* ID of device containing */ /* a directory entry for this file */ dev_t st_rdev; /* ID of device */ /* This entry is defined only for */ /* char special or block special files */ nlink_t st_nlink; /* Number of links */ uid_t st_uid; /* User ID of the file's owner */ gid_t st_gid; /* Group ID of the file's group */ off_t st_size; /* File size in bytes */ time_t st_atime; /* Time of last access */ time_t st_mtime; /* Time of last data modification */ time_t st_ctime; /* Time of last file status change */ /* Times measured in seconds since */ /* 00:00:00 UTC, Jan. 1, 1970 */ long st_blksize; blkcnt_t st_blocks; /* Preferred I/O block size */ /* Number of 512 byte blocks allocated*/

Błędy zwracane przez stat() EACCES - Search permission is denied for a component of the path prefix. EINTR function. A signal was caught during the execution of the stat() or lstat() ELOOP path. Too many symbolic links were encountered in translating ENAMETOOLONG The length of the path argument exceeds PATH_MAX, or the length of a path component exceeds NAME_MAX while _POSIX_NO_TRUNC is in effect. ENOENT - The named file does not exist or is the null path- name. ENOLINK - The path argument points to a remote machine and the link to that machine is no longer active. ENOTDIR - A component of the path prefix is not a directory. EBADF - The fildes argument is not a valid open file

Dowiązania sztywne Organizacja logiczna systemu plików: Katalogi Metryczki (inode information node) z grubsza odpowiada strukturze stat Dane czyli alokacja (plik może nie zawierać danych) Katalog: Mapuje nazwy na numery metryczek Nie przechowuje więcej informacji o pliku! do danej metryczki mogą występować odwolania z wielu katalogów! Przykład: wpisy.,.. Dowiązanie sztywne (hard link) powiązanie: nazwametryczka Numery metryczek sa uniklane w obrębie danego systemu plików, więc hard-link tylko w obrębie jednego fs

katalog (wiąże nazwy z nr inode) tablica inode- logicznie (zawiera atrybuty plików) nr inode - metryczka dir1... file1.txt dir2... 100 1 110 111 / dir1 dir2 file1.txt 1 /... 100 dir1... 110 file1 111 dir2 112...

Dowiązania symboliczne (soft- sym-links) Dowiązanie symboliczne to specjalny plik, który zawiera nazwę wskazywanego pliku Dowiązanie może mieć postać:../../src., /usr/bin/ls,./files/abc.txt Kernel w typowych funkcjach przetwarzających ścieżki podąża za sym-linkami (zob. lstat() jako jeden z wyjatków) Symlinki mogą przekraczać granice systemów plików! Obsługa s-l jest wolniejsza od h-l int symlink(const char *oldpath, const char *newpath); int link(const char *oldpath, const char *newpath);

Wywołanie fcntl() #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock); file control - różnego rodzaju operacje na pliku reprezentowanym przez deskryptor F_DUPFD jak dup() F_GETFD, F_SETFD pobiera/ustawia flagi deskryptora (jest jedna: FD_CLOEXEC) F_GETFL / F_SETFL pobiera ustawia flagi: O_RD, O_WR, O_RDWR, O_APPEND, O_NONBLOCK, O_ASYNC, O_DIRECT (ale nie mode) F_GETLK, F_SETLK, F_SETLKW zob. Dalej F_GETOWN, F_SETOWN, F_GETSIG and F_SETSIG ustalają proces i sygnał wysyłany z gniazda BSD (socket)

Wywołanie fcntl() #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock); F_SETLEASE, F_GETLEASE blokada plików, zob. dalej F_NOTIFY powiadomienie o zmianach w fs: fd musi reprezentować katalog Poniższe flagi mogą być traktowane jak maski bitowe ( ) DN_ACCESS: read DN_MODIFY: write,truncate DN_CREATE: open, creat, mknod, mkdir, link, symlink, rename DN_DELETE: unlink, rename - do innego kat., rmdir DN_RENAME: rename - w tym kat. DN_ATTRIB: chown, chmod Zmiana sygnalizowana przez SIGIO; DN_MULTISHOT jeśli chcemy otrzymywać je stale

Wywołanie ioctl() #include <unistd.h> #include <sys/ioctl.h> int ioctl(int fd, int request,...); DIOxxx FIOxxx MTIOxxx SIOxxx TIOxxx <disklabel.h> - niskopoziomowy dostep do etykiety i tabl partycji dysku <ioctl.h> - pliki <mtio.h> - pamięci taśmowe <ioctl.h> - gniazda <ioctl.h> - terminale ioctl() - "catch all" dla pozostalych operacji I/O ustawianie różnego rodzaju flag obsługa urządzeń - np. linie sterujące portów szeregowych niskopoziomowe operacje na dyskach - tablica partycji, itp. niskopoziomowe operacje na taśmach - przewijanie, omijanie archiwów operacje na sterownikach kart sieciowych...

umask, umask() #include <sys/types.h> #include <sys/stat.h> mode_t umask(mode_t cmask); Ustawia zmienną umask w deskryptorze procesu Zwraca poprzednią maskę (nie ma sytuacji błędnej) maska: taka jak prawa dostępu dla open/creat, gjb@fox:/tmp> umask 22 gjb@fox:/tmp> touch a; ls -l a -rw-r--r-- 1 gjb... gjb@fox:/tmp> umask 777 gjb@fox:/tmp> touch b używana przy tworzeniu nowego pliku gjb@fox:/tmp> ls -l b lub katalogu, ---------- 1 gjb... maska jest odejmowana od uprawnień w momencie tworzenia pliku, np. dla maski 022 skasowane bedą bity w dla og (og-w) Proces demon powinien ustawiać umask gjb@fox:/tmp> touch a; ls -l a -rw-r--r-- 1 gjb...

Operacje na katalogach Przypomnienie: katalog jest plikiem prawie zwykłym - kilka funkcji systemowych interpretuje go inaczej niż plik #include <unistd.h> int chdir(const char* path); zmienia aktualny katalog procesu int fchdir(int fd); zmienia aktualny katalog na zapamiętany w deskryptorze (katalogi można otwierać przy pomocy open() ale tylko w trybie R) #include <unistd.h> int mkdir (const char *path, mode_t perms); Tworzy katalog pusty katalog, dodaje pozycje. i.. Uwaga: zapewne chcemy ustawic co najmniej u+x (inaczej nie będzie dostepu do plików)

Operacje na katalogach Przypomnienie: katalog mapuje nazwę na numer inode, faktyczna wewnętrzna struktura katalogu jest ukryta #include <dirent.h> DIR* opendir(const char* dirname); zwraca wskaźnik na uchwyt do katalogu struct dirent* readdir(dir* dirp); odczytuje kolejne struktury dirent struct dirent { ino_t d_ino; char d_name[];... } void rewinddir(dir* dirp); przewija do początku void seekdir(dir* dirp, long int loc); long int telldir(dir* dirp); zwraca aktualną pozycję, przewija do wskazanej pozycji

Prosty ls #include <dirent.h> int listdir(const char *path) { struct dirent *entry; DIR *dir_p; dir_p = opendir(path); if (dir_p == NULL) { /*... */ return -1; } while((entry = readdir(dir_p))) printf( %9.9d %s, (long)entry->d_ino, entry->d_name); closedir(dir_p); return 0; }

Zajmowanie plików i rekordów Atomowość operacji na plikach wykraczających poza read()/write() (np. read() -> write() ) wymaga mechanizmu synchronizacji Można użyć jednego z wielu dostępnych mechanizmów, ale lepszy byłby mechanizm ściśle związany z plikami (a nie np. semafory IPC) Istnieje kilka API (z przyczyn historycznych), w praktyce jeden mechanizm na poziomie kernela i ewentualnie kilka API Niezależnie od rozwiązania API, dwa tryby zajmowania: advisory locking (zalecane) - blokada dla tego kto jej używa, tj. używa funkcji blokad mandatory locking (obowiązkowe) nie da się obejść blokady (niedozwolone I/O będzie blokowane lub EAGAIN jeśli tryb NONBLOCK) domyślnie: advisory, mandatory gdy prawa: SGID+,g-x

Po co zajmujemy pliki? #define SEQFILE seqno /*nazwa pliku*/ #define MAXBUFF 100 int main(int argc, char **argv) { int fd, i, n, pid, seqno; char buff[maxbuff +1]; pid = getpid(); if (( fd=open(seqfile,2) ) < 0 ) err_sys( can t open %s, SEQFILE); for ( i=0; i<20; i++ ) { my_lock(fd); /*blokada*/ lseek(fd, 0L, 0); /*przewiń*/ if (( n=read(fd,buff,maxbuff) ) <=0 ) err_sys( read error ); buff[n] = \0 ; if((n=sscanf(buff, %d\n, &seqno))!=1) err_sys( sscanf error ); printf( pid=%d, seq#=%d\n,pid, seqno); seqno++; sprintf(buff, %03d\n, seqno); n=strlen(buff); lseek(fd, 0L, 0); /*przewiń*/ if (write (fd,buff,n)!=n) err_sys( write error ); my_unlock(fd);/*zdjęcie blokady*/ } } wykonanie: pid = 186, 187,... 187, 186, seq#=1 seq#=1 seq#=10 seq#=2

Zajmowanie plików i rekordów Styl BSD zajmowany jest cały plik #include <sys/file.h> int flock(int fd, int operation); LOCK_SH shared lock. LOCK_EX exclusive lock. LOCK_UN remove an existing lock Styl SYSV zajmowany jest fragment pliku od bieżącej pozycji, size B do przodu lub do tyłu (jeśli ujemne): #include <unistd.h> int lockf(int fildes, int function, off_t size); F_ULOCK F_LOCK F_TLOCK F_TEST unlock locked sections lock a section for exclusive use test and lock a section for exclusive use test a section for locks by other processes

Zajmowanie plików i rekordów flock() zajmuje tylko całe pliki lockf() ma tylko jeden typ blokady i zakłada, że plik otwarty do zapisu Obydwa rozwiązania są niewystarczajace, dlatego stosujemy fcntl: #include <fcntl.h> int fcntl(int fildes, cmd, struct flock *lck); zwraca: EBADF, EAGAIN/EACCES (obszar zajęty), EINTR (blokada i sygnał), EDEADLK (cykl) cmd F_GETLK, zwraca informacje o blokadach (jeśli są) F_SETLK, zakłada blokadę wskazanego typu i zakresu F_SETLKW, j.w. blokujące struct flock { short int short int off_t off_t pid_t } l_type; l_whence; l_start; l_len; l_pid; /* F_RDLCK, F_WRLCK, or F_UNLCK. */ /* SEEK_SET, SEEK_CUR, or SEEK_END */ /* zwrotnie */

Zajmowanie plików i rekordów - fcntl() l_whence - jak w lseek, jeśli l_len==0 to zajęcie zawsze do końca pliku (także "przyszłego" końca), można też zajmować poza aktualny koniec (analogicznie jak pozycjonowanie w lseek() ), sąsiadujące zajęte obszary są sklejane, zakończenie procesu zwalnia jego zajęcia, zamknięcie deskryptora też zwalnia zajęcia (nawet jeśli proces ma inne deskryptory do tego pliku!), zajęcia nie są dziedziczone przy fork(), ale nie są usuwane przy exec(), zajęcia są globalne - na poziomie pliku.

Inne polecenia fcntl() - lease Lease Solaris, Linux od kernela 2.4 F_SETLEASE: arg przyjmuje wartość: F_RDLCK, F_WRLCK, F_UNLCK F_GETLEASE: zwraca wartości j.w. Lease: jak flock() czyli R,...,R/W, ale: Konfliktująca operacja open()/truncate() jest zawieszana, a do właściciela pliku wysyłany jest sygnał SIGIO F_RDLCK (O_RD) read lease, notyfikacja gdy write/trunc F_WRLCK write lease, notyfikacja gdy read/write/trunc Właściciel w takiej sytuacji powinien oddać lease poprzez F_UNLOCK Jeśli nie zrobi tego w czasie /proc/sys/fs/lease-break-time lease zostanie mu zabrany ( lease break ) Po oddaniu lub zabraniu lease, konfliktująca operacja może być kontynuowana

Zaawansowane funkcje I/O #include <sys/uio.h> ssize_t readv(int fildes, const struct iovec *iov, int iovcnt); ssize_t writev(int fildes, const struct iovec *iov, int iovcnt); struct iovec { void size_t *iov_base; iov_len; } scattered read / gather write Zastosowanie: atomowość operacji (istotne np. przy UDP) unikamy kopiowania ssize_t pread(int fildes, void *buf, size_t nbytes, off_t offset); ssize_t pwrite(int fildes, void *buf, size_t cont, off_t offset); Zastosowanie: atomowe pozycjonowanie i odczyt lub zapis lseek(); read() lub write() nie jest równoważny

Zaawansowane funkcje I/O #include <sys/types.h> #include <sys/uio.h> #include <unistd.h> iovcnt = sizeof(iov) / sizeof(struct iovec); ssize_t bytes_read; bytes_read = readv(fd, iov, int fd; char buf0[20]; iovcnt); char buf1[30];... char buf2[40]; int iovcnt; struct iovec iov[3]; iov[0].iov_base = buf0; iov[0].iov_len = sizeof(buf0); iov[1].iov_base = buf1; iov[1].iov_len = sizeof(buf1); iov[2].iov_base = buf2; iov[2].iov_len = sizeof(buf2);

Zawansowane I/O - poll int poll(struct pollfd fds[], nfds_t nfds, int timeout); struct pollfd { int fd; short events; short revents; } Funkcja jest zamiennikiem SYSV select() (z BSD) Oczekuje na zdarzenia podane w tablicy fds[]; timeout określony jest w ms; -1 = niesk.; 0 bez blokoania Zdarzenie (pollfd) : deskryptor, oczekiwany typ zdarzenia, zdarzenie, które wystąpiło Zwraca: liczbę deskryptorów, na których wystąpiły zdarzenia; 0 timeout; -1 / errno -błąd Zdarzenia (zob. też powiązanie ze STREAMS): POLLIN można czytać POLLRDNORM można czytać dane zwykłe POLLRDBAND można czytać dane wysoko priorytetowe POLLPRI j.w. POLLOUT można pisać POLLWRNORM j.w. POLLWRBAND można pisać priorytetowe dane POLLMSG jest M_SIG lub M_PCSIG z sygnałem SIGPOLL

Zawansowane I/O - poll int poll(struct pollfd fds[], nfds_t nfds, int timeout); struct pollfd { int fd; short events; short revents; } Zdarzenia zwracane - dodatkowo: POLLERR błąd POLLHUP rozłączenie POLLNVAL zły deskryptor Ustawienie flagi I_SETSIG poprzez ioctl(fd, I_SETSIG, arg) powoduje wysłanie sygnału SIGPOLL gdy zajdzie określone zdarzenie; pozwala to na realizację asynchronicznego I/O (sterowanego zdarzeniami); następujące zdarzenia mogą być przekazane jako maska bitowa w arg ioctl(): S_RDNORM; S_RDBAND; S_HIPRI, S_OUTPUT, S_WRNORM, S_ERROR, S_HANGUP, S_BANDURG (gdy razem z S_RDBAND wysyła SIGURG)

Zawansowane I/O - poll int poll(struct pollfd fds[], nfds_t nfds, int timeout); struct pollfd { int fd; short events; short revents; } Zdarzenia zwracane - dodatkowo: POLLERR błąd POLLHUP rozłączenie POLLNVAL zły deskryptor Ustawienie flagi I_SETSIG poprzez ioctl(fd, I_SETSIG, arg) powoduje wysłanie sygnału SIGPOLL gdy zajdzie określone zdarzenie; pozwala to na realizację asynchronicznego I/O (sterowanego zdarzeniami); następujące zdarzenia mogą być przekazane jako maska bitowa w arg ioctl(): S_RDNORM; S_RDBAND; S_HIPRI, S_OUTPUT, S_WRNORM, S_ERROR, S_HANGUP, S_BANDURG (gdy razem z S_RDBAND wysyła SIGURG)

VFS

Podstawy konstrukcji VFS Tablica plików per-proces odwołujemy się przez liczbowe deskryptory zwracane przez open(), pipe(), socket(),... dziedziczona przy fork(), nie modyfikowana (poza close-on-exec) przez exec...(), przechowuje tylko flagę c-o-e oraz wskazanie na struct file. Systemowa lista plików (struct file), przechowuje informacje o otwartym pliku: pozycję, flagi (append, read/write, no-block) wskazuje na strukturę vnode VNODE Table - Systemowa tablica wirtualnych metryczek (struct vnode) jeden używany plik odpowiada zawsze dokładnie jednemu vnode vnode zapewnia wirtualizację, czyli niezależność operacji od typu systemu plików (fizycznej implementacji)

Tablica otwartych plików ufchunk user uf_ofile[] 0 1 2.. proc *file lista otwartych plików w systemie N U L L ufchunk ufchunk 0 1 2.. 0 1 2.. NFPCHUNK = 24 tworzy open() create() dup() cred file file file file file vnode vnode vnode vnode vnode filock filock filock N U L L

struct file Struktury file reprezentują otwarte przez procesy pliki Struktury spięte są w listę (nie ma problemów wydajnościowych, bo lista nigdy nie jest przeszukiwana) struct file { struct file *f_next, *f_prev; off_t f_offset; cnt_t f_count; ushort f_flag; mode_t f_mode; struct vnode *f_vnode; struct cred *f_cred; } struct file { // Linux! mode_t f_mode; loff_t f_pos; unsigned short f_flags; unsigned short f_count; // pola związane z odczytem // z wyprzedzeniem unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; struct file *f_next, *f_prev; int f_owner; struct inode * f_inode; struct file_operations *f_op; unsigned long f_version; void *private_data; };

struct vnode Uogólnienie inode (zob. struct stat) Dokładnie jeden VNode na używany plik (nie koniecznie otwarty!) struct vnode { u_short u_long struct vfs struct vnodeops struct vfs struct stdata struct page enum vtype dev_t caddr_t struct filock kmutex_t... } v_flag; v_count; *v_vfsmountedhere; *v_op; *v_vfsp; *v_stream; *v_pages; v_type; v_rdev; v_data; *v_filocks; v_lock; /* /* /* /* /* /* /* /* /* /* /* /* vnode flags */ reference count */ ptr to vfs mounted here */ vnode operations */ ptr to containing VFS */ associated stream */ vnode pages list */ vnode type */ device (VCHR, VBLK) */ private data for fs */ ptr to filock list */ protects vnode fields */

Struktura vnode v_flag v_count - liczba odwołań - dowiązań *v_vfsmountedhere *v_op - opis typu systemu plików *v_vfsp - struktura wirtualnego systemu plików *v_stream *v_pages v_type VNON v_rdev - major & minor number VREG v_data - np. struct inode VDIR *v_filock VBLK VROOT VNOMAP VDUP VNOSWAP VNOMOUNT VVISSWAP regular VCHR VLINK VFIFO pipe VXNAM - XENIX shared data segment VBAD bad file

vnode->v_op Pole v_op pozwala na realizację kernelowych funkcji plikowych niezależnie od faktycznej implementacji systemu plików v_op pokazuje na tablicę operacji implementowanych przez dany system plików Operacje są przykryte przez makra VOP_... Dla argumentu arg kernel na każdym vnode może wykonać np. operację open: VOP_OPEN(vp, arg) co jest rozwijane na: (*(vp->v_op->vop_open))(vp, arg) vnodeops: VOP_LOOKUP, VOP_CREATE, VOP_MKNOD, VOP_OPEN, VOP_CLOSE, VOP_ACCESS, VOP_GETATTR, VOP_SETATTR, VOP_READ, VOP_WRITE, VOP_IOCTL, VOP_FCNTL, VOP_POLL, VOP_KQFILTER, VOP_REVOKE, VOP_MMAP, VOP_FSYNC, VOP_SEEK, VOP_REMOVE, VOP_LINK, VOP_RENAME, VOP_MKDIR, VOP_RMDIR, VOP_SYMLINK, VOP_READDIR, VOP_READLINK, VOP_ABORTOP, VOP_INACTIVE, VOP_RECLAIM, VOP_LOCK, VOP_UNLOCK, VOP_ISLOCKED, VOP_BMAP, VOP_PRINT, VOP_PATHCONF, VOP_ADVLOCK, VOP_LEASE, VOP_WHITEOUT, VOP_GETPAGES, VOP_PUTPAGES, VOP_STRATEGY, VOP_BWRITE, VOP_GETEXTATTR, VOP_SETEXTATTR, VOP_LISTEXTATTR

vnode->v_op int VOP_LOOKUP(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp); Szuka pliku po nazwie; dvp: vnode katalogu, vpp: zwracany vnode; cnp: struktura używana do przetwarzania nazw scieżek int VOP_OPEN(struct vnode *vp, int mode, kauth_cred_t cred); Otwiera plik int VOP_READ(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t cred); Czyta z pliku; uio: uogólniona struktura buforowa

vnode przydzielany gdy open() (o ile już nie istnieje) ale także: exec(), operacje na katalogach i inne sytuacje nie są spięte w globalną listę; dostęp np. przez struct file; w celu przyśpieszenia dostępu do vn stosuje się też dodatkowe struktury danych - zob. DNLC, specfs) blokady realizowane są poprzez listę struktur filock przywiązanych do vn

VFS W systemie plików: różne typy systemów (UFS, NFS, EXFS, XFS, tmpfs, procfs, sysfs, fdfs,...) różne zamontowane systemy (jednego lub różnych typów) vnode pozwala na obsługę operacji w różnych typach systemów plików, ale jak organizujemy to na poziomie montowań? mount [-opcje] [-f typ.systemu] [-o opcje.tego.systemu] [urządzenie] [katalog] % mount -f ufs -o ro /dev/dsk/c0t0d0s0 /usr/local/files

montowania / / /bin /etc /bin /usr /etc /usr/local mount -f ufs /dev/hda0 /usr/local /usr /usr/local

VFS mount - zamontowanie systemu plików unmount - zdemontowanie systemu plików fsck - sprawdzenie spójności i poprawności fs format fmthard - formatowanie dysku mkfs - tworzenie systemu plików struct vfssw - tablica przełączania VFS typy systemów plików i dostępne w nich operacje struct vfs - struktura VFS - dla każdego zamontowanego systemu plików

VFS Tablica rozdzielcza wirtualnego systemu plików struct vfssw: typedef struct vfssw { char *vsw_name; int (*vsw_init)(); struct vfsops *vsw_vfsops; } vfssw_t; struct vfssw vfssw[] { {"ufs", ufsinit, &ufs_vfsops}, {"proc", prinit, &prvfsops} }; vsw_vfsops definiuje funkcje danego fs (analogicznie do v_op): vfs_mount, vfs_unmount, vfs_root, vfs_statvfs, vfs_sync, vfs_vget, vfs_mountroot; makra: VFS_MOUNT, VFS_UMOUNT, VFS_ROOT, itd.

Operacje na vfs typedef struct vfsops { int (*vfs_mount)(); int (*vfs_unmount)(); int (*vfs_root)(); int (*vfs_statvfs)(); int (*vfs_sync)(); int (*vfs_vget)(); int (*vfs_mountroot)(); int (*vfs_swapvp)(); } vfsops_t; #define VFS_MOUNT(vfsp, mvp, uap, cr) (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr) #define VFS_UNMOUNT(vfsp, cr) (*(vfsp)->vfs_op->vfs_unmount)(vfsp, cr) #define VFS_ROOT(vfsp, vpp) (*(vfsp)->vfs_op->vfs_root)(vfsp, vpp) #define VFS_STATVFS(vfsp, sp) (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp) #define VFS_SYNC(vfsp, flag, cr) (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr) #define VFS_VGET(vfsp, vpp, fidp) (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp) #define VFS_MOUNTROOT(vfsp, init) (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, init) #define VFS_SWAPVP(vfsp, vpp, nm) (*(vfsp)->vfs_op->vfs_swapvp)(vfsp, vpp, nm)

struct vfs każda struct vfs opisuje zamontowany system plików struktury vfs spięte w listę nowa struktura tworzona w wyniku wywołania mount() usuwana gdy umount dla każdego vfs przechowujemy wskaźnik na przykryty vnode - i (co waźniejsze!) przykryty vnode musi zawierać wskaźnik na zamontowany vfs dla każdego vfs musimy też przechować: typ, liczbę podmontowanych w nim vfs(!) oraz informację o fizycznym fs (device)

typedef struct vfs { struct vfs struct vfs *vfs_next; /* next VFS in VFS list */ struct vfsops *vfs_op; /* operations on VFS */ struct vnode *vfs_vnodecovered; /* vnode mounted on */ u_long vfs_flag; /* flags */ u_long vfs_bsize; /* native block size */ int vfs_fstype; /* file system type index */ fsid_t vfs_fsid; /* file system id */ caddr_t vfs_data; /* private data */ dev_t vfs_dev; /* device of mounted VFS */ u_long vfs_bcount; /* I/O count (accounting) */ u_short vfs_nsubmounts; /* immediate sub-mount count */ struct vfs *vfs_list; /* sync list pointer */ struct vfs *vfs_hash; /* hash list pointer */ kmutex_t } vfs_t; vfs_reflock; /* mount/unmount/sync lock */

Struktury vfs Lista zamontowanych systemów plików VFS VFS vfs_next vfs_next vfs_nodecovered root vnode super block root vnode super block VNode v_vfsp Inode (v_data) vfs_op VNode vfsops vfsops v_vfsmountedhere v_vfsp vfs_vfsops vfssw Tablica dostępnych typów systemów plików Inode (v_data) V-węzeł katalogu, na którym zamontowano system plików

mount() - szkic mount(spec, dir, flags, type, data_ptr, data_len); sprawdzamy czy spec poprawny lookuppn() - otrzymujemy v-node punktu montowania (dir) - mp sprawdzamy czy dir poprawny, czy katalog, czy nie ma na nim innych montowań, itp. znajdujemy vfs w vfssw po nazwie (type) wywołujemy vfs_init() dla tego vfs alokujemy struct vfs, i: dodajemy ją do listy vfs ustawiamy vfs_op wg vfssw ustawiamy vfs_vnodecovered w vfs oraz vfs_mountedhere w vn wywołujemy VFS_MOUNT alokuje i inicjuje dane prywatne vfs, lokalizuje rootdir dla vfs i inicjuje jego vn (VFS_ROOT) zwiększamy o 1 vfs_nsubmounts w vfs punktu montowania

DNLC Directory Name Lookup Cache Pamięć podręczna nazw Przyśpiesza operacje przetwarzania scieżek / wyszukiwania w katalogach (VOP_LOOKUP) pozwala na szybką lokalizację vnode po nazwie struktury cache mapują nazwę na vnode organizacja cache (struct ncache): listy hash listy LRU nazwa, wskaźnik na vn, wskaźnik na katalog macierzysty główna funkcja: dnlc_lookup() - zwraca wskaźnik na vnode po nazwie; dnlc_enter() - dodaje vnode do cache uwaga: długie nazwy nie będą cachowane

DNLC Directory Name Lookup Cache /* * Note namlen is a uchar_t to conserve space * and alignment padding. The max length of any * pathname component is defined as MAXNAMELEN * which is 256 (including the terminating null). * So provided this doesn't change, we don't include the null, * we always use bcmp to compare strings, and we don't start * storing full names, then we are ok. The space savings are worth it. */ typedef struct ncache { struct ncache *hash_next; /* hash chain, MUST BE FIRST */ struct ncache *hash_prev; struct vnode *vp; /* vnode the name refers to */ struct vnode *dp; /* vnode of parent of name */ int hash; /* hash signature */ uchar_t namlen; /* length of name */ char name[1]; /* segment name - null terminated */ } ncache_t;

DNLC Directory Name Lookup Cache void void void vnode_t void void int void int void dnlc_init(void); dnlc_enter(vnode_t *, char *, vnode_t *); dnlc_update(vnode_t *, char *, vnode_t *); *dnlc_lookup(vnode_t *, char *); dnlc_purge(void); dnlc_purge_vp(vnode_t *); dnlc_purge_vfsp(vfs_t *, int); dnlc_remove(vnode_t *, char *); dnlc_fs_purge1(struct vnodeops *); dnlc_reduce_cache(void *); Linux: struct dentry { struct hlist_bl_node d_hash; struct dentry *d_parent; struct qstr d_name; struct inode *d_inode; unsigned char d_iname[...];/* small names /*... */ union { struct list_head d_lru; /* LRU list */ /*... */ }; struct list_head d_child; /* child of parent list */ struct list_head d_subdirs; /* our children funkcje dnlc_purge_*() usuwają odwolania do danego vn (gdy przestaje być on używany LUB gdy odmontowany jest caly vfs)

Przykładowe typy systemów plików UFS (FFS) standardowy unixowy system nowej generacji, pochodzi z BSD, bazuje na nim m.in. system ext2, ext3 Inne systemy dyskowe: S5 (historyczny), XFS (SGI), JFS (IBM), Raiserfs (Linux) Tempfs system w pamięci Procfs informacje o procesach parametry i struktury jądra (także sysfs) fdfs deskryptory procesu NFS Network File System (BSD/SunOS) SPECFS (SVR4) - system obsługujący urządzenia

ufs Informacje organizacyjne: Super blok: parametry dysku: wielkość bloku, liczba bloków, położenie tabeli inode, root-dir, itd. Mapa bitowa wolnych bloków Tablica I-Node Root-dir W przypadku grup cylindrów informacje te są obecne w każdej grupie

UFS - superblock wielkość sumaryczna, wielkość bloku, wielkość fragmentu liczba inode, rozmiar inode liczniki: wolnych bloków, wolnych inode czas modyfikacji grupa cylindrów autonomiczna pod jednostka wewnątrz fs decentralizuje zarządzanie plikami; parametry: numer grupy tego SB, wielkość grypy cyl, inne parametry grupy cyl. licznik montowań, czas ostatniego montowania, scieżka montowania (tylko informacyjnie) flaga "czyste odmontowanie" położenie: mapy wolnych blokow, tablicy inode, root-dir, bloków danych

System plików UFS Alokacja I-node: 12 bloków bezpośrednich (0-11) jeden blok pośredni (12) 1-go poziomu pokazuje na blok w którym 2048 adresów bloków jeden blok pośredni (13) 2-go poziomu pokazuje na blok w którym 2048 adresow bloków 1-go poziomu jeden blok pośredni (24) 3-go poziomu pokazuje na lok w którym 2048 adresów bloków 2-go poziomu Jednostka alokacji: blok 8 KB Jednostka adresowania: long int (32 bit) przechowuje numery bloków (i_addr[]) 8192 * 12 = 98304 B 8192 * ( 12 + 2048) = 16 MB 8192 * (12+2048 + 2048^2) = 3,4 ^ 10 B 8192 * (12+2048 + 2048^2 + 2048^3) = 7,4 ^ 13 B = 70 trylionów B = 70 TB

VxFS Komercyjny system opracowany przez Veritas (koniec lat 80-tych), dostępny dla: AIX, HP-UX, Linux, Solaris Podstawowe założenie: alokacja wykorzystuje extenty (extents), co rozwiązuje problem bloków pośrednich Blok może mieć rozmiar 1,2,4,8 KB Extent: możliwe jak najdłuższy ciąg kolejnych bloków, np. przy sekwencyjnym zapisie, pierwszy e. będzie 2x dłuższy od zapisu; po zamknięciu pliku e. jest skracany możliwa jest ręczna pre-alokacja extentów (gdy z góry wiemy jaki będzie rozmiar pliku) oraz zmiana alokacji e. Inne cechy: Caching advisory: direct I/O, unbuffered I/O, data synchronous I/O Zróżnicowana obsługa awarii/błedów (disable/nodisable), możliwa próba naprawy w locie Dziennik (intent log) Organizacja: meta-informacja też jest przechowana w plikach: structural fileset, dzięki temu meta informacja też jest dowolnie rozszerzalna ; możliwa też dynamiczna zmiana fs w trakcie pracy

Inne dyskowe systemy plików ext2 (Linux) b. podobny do oryginalnego UFS ext3 (Linux, 2001) ext2 + dziennik, indeks Htree dla dużych katalogów, zgodny wstecznie z ext2, journal ext4 (Linux, 2008) obsługa b. dużych fs (do 1 EiB - 2^60B), obsługa extents, prealokacja miejsca (fallocate()), opóźniona alokacja (zapobiega fragmentacji gdy wielu piszących) inne udogodnienia związane z alokacją, lepsza obsługa dziennika, zgodny wstecznie z ext2/3 ReiserFS stworzony od zera, dziennik meta-danych, mechanizmy eliminujące fragmentację, brak kwot (quota) JFS (IBM) 64-o bitowy, nie tylko Linux (AIX, inne), dziennik metadanych, organizacja wewn. katalogów wykorzystuje B-drzewa, dynamiczna alokacja i-node, kompresja, extents, interesujący głównie z historycznego punktu widzenia XFS (SGI), 64-o bitowy, nie tylko Linux (IRIX, inne), specjalizowany do wydajnego I/O i dużych plików, extents, write barriers, sparse files, direct I/O, guaranteed-rate I/O

Systemy plików - podsumowaniue Tematy nie omawiane: VFS a VM (patrz dalej VM) VFS a SMP (multi-cpu) Media wymienne (CD/DVD, USB,...) Specjalne montowania: loop, Squashfs, AUFS (LiveCD) FS w różnych odmianach Unixa Zaawansowane systemy plików (multi-wolumen, software-raid, np. VxFS)

fdfs przykład systemu wirtualnego Przykład w skrypcie - łączy zawartość plików i stdin: cat./myfile1.txt /dev/fd/0./myfile2.txt >./outfile.txt Pseudo-system nie mającego odzwierciedlenia w faktycznym systemie dyskowym Pozwala na dostęp do deskryptorów (0,1,2,...) - tak jak do plików Pozwala na wygodny dostęp do deskryptorów takich jak np. stdio, stdout, stderr z poziomu skryptów Uwaga: inny obraz zawartości dla każdego procesu(!) Montowanie: mount -t fdfs /dev/fd /dev/fd Przykład operacji: fd=open( /dev/fd/0, O_RD);

Procfs (sysfs) Pseudo file system - /proc Interfejs do struktur kernela (początkowo- deskryptorów procesów), tak aby można było ograniczyć konieczność stosowania mechanizmu setuid-root Początkowo jeden plik na każdy proces, nazwa taka jak pid, operacje na procesie poprzez ioctl() Następnie dodano pliki i katalogi reprezentujące różne moduły i struktury systemowe Obecny trend (BSD) to wyniesienie informacji o systemie do sysfs (w procfs zostaje tylko inf. o procesach) Operacje na procfs to operacje na strukturach jądra systemu

Procfs dane procesu /proc/pid/cmdline, linia polecenia uruchomienia procesu gjb@skinner:/proc/29144$ more status Name: sshd State: S (sleeping) /proc/pid/cwd, symlink do aktualnego katalogu Tgid: 29144 Pid: 29144 /proc/pid/environ, zmienne środowiskowe PPid: 29136 TracerPid: 0 Uid: 1003 1003 1003 1003 /proc/pid/exe, symlink do pliku wykonywalnego Gid: 100 100 100 100 /proc/pid/fd/, deskryptory plików Groups: 100 108 112 /proc/pid/root, symlink do korzenia fs /proc/pid/status, status ii podstawowe statystyki /proc/pid/task, katalog z linkami do utworzonych przez ten proces procesów FDSize: 32 VmPeak: 6512 kb VmSize: 6508 kb Threads: 1... voluntary_ctxt_switches: 642 nonvoluntary_ctxt_switches: 1

Procfs dane systemu /proc/cpuinfo contains information about the cpu, such as its vendor (and cpu family, model and model names which should allow you to identify the cpu) and its speed (cpu MHz), cache size, number of siblings and cores and cpu flags. It contains a value called "bogomips", which is frequently mistaken to measure CPU speed like a benchmark, while it doesn't actually measure any sensible (for endusers) value at all. It is just a side-effect of kernel timer calibration and yields highly varying values depending on CPU type, even at equal clock speeds. /proc/devices is a list of character and block devices sorted by device id but giving the major part of the /dev name too. /proc/diskstats gives some information (including device numbers) for each of the logical disk devices /proc/filesystems is a list of the file systems supported by the kernel at the time of listing /proc/interrupts, /proc/iomem, /proc/ioports and the directory /proc/irq give some self explanatory details about the devices (physical or logical) using the various system resources.

cat /proc/cpuinfo processor : 0 vendor_id : AuthenticAMD cpu family : 15 model : 43 model name : AMD Athlon(tm) 64 X2 Dual Core Processor 4200+ stepping : 1 cpu MHz : 2200.414 cache size : 512 KB physical id : 0 siblings : 2 core id : 0 cpu cores : 2 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 1 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt lm 3dnowext 3dnow pni lahf_lm cmp_legacy ts fid vid ttp bogomips : 4406.14

cat /proc/diskstats 8 0 sda 12570396 284314 282056278 29556260 14478215 40908507 443503064 261844252 0 36204972 291402364 8 1 sda1 12854751 282056270 55437851 443502976 8 16 sdb 86787382 5178040 3452622634 201469292 26682139 51904455 630174030 489189356 0 157598096 690832496 8 17 sdb1 92037689 3452622626 78805247 630174014 Format: Major, minor, nazwa, statystyki: 1 - # of reads issued 2 - # of reads merged, field 6 -- # of writes merged 3 - # of sectors read 4 - # of milliseconds spent reading 5 - # of writes completed 7 - # of sectors written 8 - # of milliseconds spent writing 9 - # of I/Os currently in progress 10 - # of milliseconds spent doing I/Os 11 - weighted # of milliseconds spent doing I/Os

cat /proc/interrupts CPU0 CPU1 0: 763911314 1187 1: 119 4 8: 0 1 9: 0 0 15: 0 13 21: 276202978 75 22: 140435125 5 24: 2620788380 1 NMI: 0 0 LOC: 763970150 763970214 ERR: 0 MIS: 74 IO-APIC-edge IO-APIC-edge IO-APIC-edge IO-APIC-level IO-APIC-edge IO-APIC-level IO-APIC-level IO-APIC-level Format: numer IRQ liczba obsłużonych przerwań per CPU sprzętowy typ przerwania urządzenie obsługujace timer i8042 rtc acpi ide1 eth0 libata VIA8237

Procfs dane systemu /proc/meminfo contains a summary of how the kernel is managing its memory /proc/modules is one of the most important files in /proc and contains a list of the kernel modules currently loaded and it gives some indication of dependencies (sometimes it isn't entirely correct) /proc/mounts is a symlink to self/mounts which contains a list of the currently mounted devices and their mount points /proc/net is a directory containing a lot of really useful information about the network stack /proc/swaps is a list of the active swap partitions, their various sizes and priority /proc/sysvipc contains memory sharing and IPC information /proc/tty contains information about the current terminals; /proc/tty/driver looks to be a list of the different types of tty available each of which is a list of those of each type. /proc/uptime is the length of time the kernel has been running since boot and spent in idle mode (both in seconds) /proc/version contains the Linux kernel version, distribution number, gcc version number (used to build the kernel) and any other pertinent information relating to the version of the kernel currently running.

Pliki specjalne i SPECFS (device special files)

pliki specjalne Mogą być zlokalizowane w dowolnym miejscu fs (np. /dev, /devices, pod-katalogach j.w.) Przykłady: /dev/sda, /dev/sdb <- dyski /dev/sda0, sda1,... <- partycje /dev/dsk/sc4d2s3 <- dysk, kontroler, napęd, partycja /dev/eth0 <- sterownik sieciowy /dev/tcp, /dev/ip <- abstrakcyjne urządzenie do tworzenia gniazd w TLI /dev/ttys0, ttys1,... <- porty szeregowe /dev/null, /dev/zero, /dev/mem <- obiekty kernela plik specjalny jest abstrakcją urządzenia

pliki specjalne dwa typy plików specjalnych: block special napędy dyskowe (interfejs blokowy) character special pozostałe (w tym dyski na niskim poziomie) Dostęp do urządzenia następuje poprzez plik specjalny (w systemie plików), w inode spec zapisany jest major oraz minor device number (dev_t) jednoznacznie identyfikujące typ i numer kolejnego) urządzenia Operacje wykonywane są poprzez sterownik zlokalizowany w kernelu UWAGA - operacje na pliku spec mogą dotyczyć: tego pliku - np. unlink(), rename() urządzenia: open(), read(), write(), ioctl()

pliki specjalne Minor dev. Number Major dev. Number b - block raw device urządzenie odpowiadajace blokowemu Pozwala na dostęp z pominięciem buforowania Obecnie uznawane za przestarzałe (BSD, Linux), można użyć flagi O_DIRECT

pliki specjalne /dev/devicex jądro block special struct bdevsw[major] 0 1 2... Struktura cdevsw: int (*d_open)(); int (*d_close)(); int (*d_read)(); int (*d_write)(); int (*d_mmap)(); int (*d_segmap)(); int (*d_poll)(); int (*d_print)(); int (*d_size)(); int (*d_ioctl)(); char *d_name; struct streamtab *d_str; (*devicex_open)(); (*devicex_close)(); (*devicex_read)(); (*devicex_write)(); (*devicex_ioctl)();... character special struct cdevsw[major] 0 1 2... minor Struktura bdevsw: int (*d_open)(); int (*d_close)(); int (*d_strategy)(); int (*d_print)(); int (*d_size)(); int (*d_ioctl)(); char *d_name;

pliki specjalne Sterownik musi też obsługiwać przerwanie. Sterownik nie musi obsługiwać wszystkich funkcji (nodev()) operacje we/wy na urządzeniu blokowym: wykonywane są poprzez funkcję d_strategy() zarządzającą transferem buforów (do/z dysku), są ściśle związane z implementacją podsystemu pamięci wirtualnej i stronicowania (VM zob. dalej), operacje read/write dla urządzenia blokowego realizowane są poprzez odczyt/zapis zamapowanych w pamięci kernela segmentów pamięci odpowiadających plikom (zob. mmap()) urządzenie "character" dla dysku to tzw. "raw device" niskopoziomowy interfejs do dysku.

pliki specjalne Dla urządzeń znakowych (nie STREAMS) typowe operacje realizowane są poprzez sekwencję open(), read()/write(), ioctl() np. ioctl() na porcie szeregowym realizuje wszystkie operacje pobrania i ustawienia stanu linii sterujacych (np. CD, CTS, DTR, DTS, itp.), zaś funkcje read i write operują na buforze portu urzadzenia znakowe STREAMS to uniwersalny mechanizm (SVR4) realizujący obsługę "komunikatów" - sieć, pty - zob. STREAMS

SPECFS SPECFS nie jest montowany, ale jest zdefiniowany w vfssw zapewnia dostęp do urządzeń niezależnie od systemu plików, w którym znajduje się plik urządzenia każdy vn związany z dev ma dodatkowo przywiązany vn tego urządzenia (czyli vn - "plikowy" i vn -"urządzenia") vn urządzenia jest "opakowany w SNODE snode zawiera informacje związane z danym urządzeniem - np. nr bajtu do wczytania różnica vn, sn: vn - v_op dla systemu plików (np. ufs_vnodeops) sn - v_op dla urządzenia (specfs_vnodeops) Dodatkowo - jedno urządzenie może być reprezentowane w wielu różnych vfs różnych typów, dlatego: s_commonvp i "zbiorczy" snode snode jest hashowany przez major i minor device number

snode / vnode

SPECFS VFS Otwarcie pliku specjalnego: tworzymy vnode "dyskowy" dołączamy sn zawierający vn typu specfs szukamy i dołączamy unikalny sn/vn danego urzadzenia (s_commonvp)

Udev i inne Problem: Fizyczne urządzenia mogą być podłączane do systemu na gorąco (przykład: dyski USB, podłączenie kabla do portu sieciowego) Sterowniki mogą być aktywowane w trakcie pracy systemu Unix (klasyczny) ma statyczny zestaw plików sterowników, ale można w każdej chwili tworzyć spec-file Udev (Linux od 2.5): Demon, bilioteka, program administracyjny (udevadm) Utrzymuje zgodność między plikami sterowników (/dev a faktycznie podłączonymi urządzeniami) Pliki konfiguracyjne określaja nazwy i reguły tworzenia plików spec Działa w userspace (komunikacja z jądrem przez gniazdo AF_NETLINK) Poprzednik: devfs devtmpfs dla lekkich dystrybucji

Sieciowy system plików NFS Wprowadzony przez Sun Microsystems w 1985 r (ówczesny SunOS == BSD). De facto standard sieciowych systemów plików w Unixie (obecna wersja v 4, najbardziej powszechna wersja: v3) Model klient-serwer, wykorzystuje zdalne wywołanie procedur (RPC) oraz standard XDR do reprezentacji danych, oryginalnie RPC zbudowano na UDP, obecnie wykorzystuje się głównie TCP Główne założenia: API identyczne jak dla lokalnych plików semantyka maksymalnie zbliżona do lokalnego (dyskowego) systemu plików wydajna implementacja

Sieciowy system plików NFS NFS v 1,2 UDP/IP NFS v 3 TCP, pliki > 4GB, zapisy asynchroniczne NFS v4 łączenie operacji, zintegrowane blokowanie, UTF-8 w nazwach, klasy atrybutów plików (nie tylko Unix)

NFS założenia Serwer eksportuje systemy plików (NFS export) Klient montuje zdalne systemy plików Montowanie zdalnego systemu plików odbywa się tak jak lokalnej partycji, zamiast special podaje się adres serwera i scieżkę: mount -f nfs server:/usr/local/src2 /usr/local/src Po stronie klienta (montującego) montowania NFS i nie-nfs mogą być nakładane tak jak normalne montowania zasobów lokalnych (czyli: np. przejście przez scieżkę może powodować przejście przez pliki lokalne, zdalne i znów lokalne) Po stronie serwera mogą być eksportowane tylko zasoby lokalne (re-eksport stwarza problemy implementacyjne, ale przedewszystkim wydajnościowe, nie jest też uzasadniony praktycznie): share -F nfs /usr/local/src System NFS jest odporny na awarie klienta i serwera: Awaria serwera powoduje tylko opóźnienie po stronie klienta Awaria klienta nie zakłóca pracy serwera, nie powoduje na nim wycieku zasobów Założenie to wymusza bezstanowość protokołu (operacje są niezależne)

NFS założenia Zastosowanie NFS nie ogranicza się do systemu Unix Awaria klienta lub serwera powinna być prosta do usunięcia Aplikacje powinny mieć dostęp do plików NFS tak samo jak dla plików lokalnych: To samo API Ta sama semantyka Taka sama konwencja nazewnicza (zwykłe nazwy scieżkowe) Klienci Unix powinni móc stosować unixowe nazewnictwo i unixowe cechy systemu plików (prawa, rozszerzenia, dowiązania symboliczne) np. powinna być możliwość zamontowania kompletnego systemu plików (wraz z /) dla maszyn bezdyskowych Wysoka wydajność Implementacja niezależna od warstwy transportowej

NFS bezstanowość Protokół NFS jest bezstanowy, co powoduje, że: W każdej operacji (np. read, write) przekazany jest komplet niezbędnych danych, a więc także pozycja w pliku operacje open i close nie modyfikują zasobów serwera W razie awarii serwera klient ponawia żądania (lub zgłasza błąd) Operacje muszą być synchroniczne: serwer musi zapisywać dane na dysk Anomalie w stosunku do semantyki plików lokalnych: Prawa dostępu są sprawdzane przy każdej operacji (a nie przy otwarciu); właściciel ma pełne prawa (prócz sprawdzenia gdy open()) Usunięcie otwartego pliku (klient zmienia nazwę otwartego pliku jeśli to on go usuwa) W systemie dyskowym pojedyncze lokalne read/write są zawsze atomowe (blokada na vnode), r/w w NFS wykonywane z różnych klientów mogą zostać wymieszane Zajmowanie pliku/rekordów wymaga osobnego mechanizmu nie może się odbywać na poziomie vnode klienta

NFS implementacja Protokół MOUNT służy do obsługi zdalnych montowań Protokół RPC portmap pozwala na lokalizację portu usługi NFS NFS (operacje plikowe) realizowany jest przez prot. NFS (na bazie RPC/XDR) nfs_mount() tworzy i inicjuje strukturę vfs po stronie klienta, zapamiętywany jest w niej adres sieciowy serwera, jest sprawdzany i zapamiętywany vnode głównego katalogu montowania (po stronie serwera sprawdzana jest dostępność zasobu, ale nie jest tworzony żaden trwały obiekt) wejście w zdalny system plików powoduje wykorzystnie VOP_LOOKUP i VFS_VGET w zdalnym systemie (wykonywane są operacje sieciowe NFS) każde wejście do kolejnego katalogu scieżki NFS skutkuje operacją sieciową NFS(!) (ale klient może stosować buforowanie) Prywatne dane vnode NFS (v_data) przechowane są w struct rnode (remote node)

NFS portmap Usługi RPC wykorzystywane przez NFS: $ rpcinfo -p program vers proto 100000 2 tcp 100000 2 udp 100003 2 udp 100003 3 udp 100003 4 udp 100003 2 tcp 100003 3 tcp 100003 4 tcp 100024 1 udp 100021 1 udp 100021 3 udp 100021 4 udp 100024 1 tcp 100021 1 tcp 100021 3 tcp 100021 4 tcp 100005 1 udp 100005 1 tcp 100005 2 udp 100005 2 tcp 100005 3 udp 100005 3 tcp port 111 111 2049 2049 2049 2049 2049 2049 32770 32770 32770 32770 32769 32769 32769 32769 644 645 644 645 644 645 portmapper portmapper nfs nfs nfs nfs nfs nfs status nlockmgr nlockmgr nlockmgr status nlockmgr nlockmgr nlockmgr mountd mountd mountd mountd mountd mountd

NFS implementacja W wyniku operacji LOOKUP (CREATE, MKDIR) serwer przekazuje do klient uchwyt (handle) Uchwyt jest jednoznaczymym identyfikatorem pliku: bez struktury, nie interpretowanym przez klienta, zawiera: Identyfikator systemu plików Nr inode Nr generacji inode inode między operacjami klienckimi mógł zostać związany z innym plikiem - taką sytuację trzeba wykryć (błąd: stale NFS file handle ) Uwaga: tak jest w przypadku NFS dla systemów Unix, NFS w innym systemie może generować uchwyty inaczej XID unikalny identyfikator transakcji RPC (nie modyfikowany przy retransmisjach)

NFS procedury RPC (v3) Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure Procedure 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: NULL - Do nothing GETATTR - Get file attributes SETATTR - Set file attributes LOOKUP - Lookup filename ACCESS - Check Access Permission READLINK - Read from symbolic link READ - Read From file WRITE - Write to file CREATE - Create a file MKDIR - Create a directory SYMLINK - Create a symbolic link MKNOD - Create a special device REMOVE - Remove a File RMDIR - Remove a Directory RENAME - Rename a File or Directory LINK - Create Link to an object READDIR - Read From Directory READDIRPLUS - Extended read from directory FSSTAT - Get dynamic file system information FSINFO - Get static file system Information PATHCONF - Retrieve POSIX information COMMIT - Commit cached data on a server to stable storage

NFS procedury i argumenty procedura argumenty wyniki GETATTR LOOKUP READLINK READ WRITE CREATE REMOVE RENAME READDIR STATFS fhandle dirfh, name status, fattr status, fhandle fattr fhandle, offset, cnt fhandle, offset, cnt, data dirfh, name, sattr drifh, name dirfh1, name1, dirfh2, name2 fhandle, cookie, count fhandle status, status, status, status status status, status, fattr/sattr atrybuty pliku (do ustawienia) cookie zwracane przez poprzednie READDIR, fhandle uchwyt pliku, dirfh uchwyt katalogu fattr, data fattr fhandle, fattr dir_entries filestats

NFS - operacje

NFS zlecenia (nie)idempotentne W razie braku potwierdzenia klient retransmituje zlecenie Jeśli zaginie potwierdzenie to zlecenie może być wykonane więcej niż raz Zlecenia idempotentne: można je wykonać kilka razy pod rząd bez skutków ubocznych Zlecenia nieidempotentne: kilkukrotne wywołanie powoduje błąd, np: k:remove, s:usunięcie, s:ack, ack ginie, k:remove, s:błąd Rozwiązanie: serwer utrzymuje cache niektórych zleceń w celu wykrywana duplikatów (tzw. pamięć podręczna retransmisji) Rozwiązanie to eliminuje większość, ale nie wszystkie problemy związane z retransmisją Pamiętane operacje: CREATE, REMOVE, LINK, MKDIR, RMDIR Jeśli błąd operacji to serwer sprawdza czy to nie duplikat

NFS- użytkownicy i uprawnienia Uprawnienia weryfikowane są przy opercji nfs_mount() i każdej operacji NFS Uwaga: nfs_mount() nie wymaga uprawnień root-a(!) Eksport systemów plików jest typowo limitowany dla konkretnych klientów (wg. adresów IP) Użytkownicy i grupy muszą posiadać jednolitą numerację w ramach systemu NFS Zaufanie do zdalnego root-a Mapowanie UID, GID: dla każdego klienta serwer może stosować mapowanie identyfikatorów, uid==0 może być zawsze mapowany na inny W wersji 4 NFS autoryzacja w oparciu o PKI

NFS dalsze szczegóły implementacji Kernel, klient Musi obsługiwać vnode-y typu NFS, operacje RPC, stos TCP/IP, itd. biod (block IO daemon) wykonują operacje I/O z wyprzedzeniem, obecnie przy nowych wersjach i implementacjach protokołu NFS nie stosowane Automountd auto mount daemon : montuje zasoby na żądanie (gdy potrzebne): w przypadku próby odwołania do określonych katalogów zdalny system plików zostanie automatycznie zamontowany: przydatne w przypadku katalogów użytkowników Serwer nfsd proces serwisowy prot. NFS, obsługuje żądania NFS Zajmowanie plików i rekordów (NLM: network lock manager) rpc.lockd osobny serwis realizujący rozproszone zajmowanie zgodne z API fcntl-lock (operacje typu callback) rpc.statd odzyskiwanie informacji w razie awarii serwera lub klienta

Komunikacja międzyprocesowa

Potoki nienazwane #include <unistd.h> #include <sys/types.h> int pipe(int fd[2]); Wywołanie systemowe pipe() tworzy potok komunikacyjny Potok jest strukturą danych w jądrze Dostęp procesu do potoku następuje poprzez dwa deskryptory typu plikowego: wejściowy fd[0] i wyjściowy fd[1] dane zapisane do fd[1] mogą zostać odczytane z fd[0] Dane zapisujemy / odczytujemy z potoku przy pomocy funkcji write() / read() Potok ma ograniczoną pojemność - PIPE_BUF (zależne od wersji systemu, zawsze >= 512) Zapisy i odczyty o wielkości nieprzekraczającej pojemności potoku są albo atomowe (dane z procesów nie mieszają się) albo blokujące (zobacz dalej)

Potoki - We/Wy write(): brak czytelników: -1, SIG_PIPE danych <= PIPE_BUF jest miejsce: atomowy zapis, nie blokujące brak miejsca: blokada, op. atomowa danych > PIPE_BUF jest miejsce: zapis cześciowy. op. nieatomowa potok pełen: blokuje, op. nieatomowa read(): brak danych, wszystkie deskr pisz. zamknięte zwraca 0 brak danych: blokuje są dane: zwraca tyle ile jest, nie zwróci więcej niż PIPE_BUF

Potoki - We/Wy O_NONBLOCK write(): danych <= PIPE_BUF tam gdzie normalnie blokada zwraca EAGAIN danych>pipe_buf, nie blokuje zapis częściowy lub EAGAIN read(): brak danych: EAGAIN, chyba, że koniec pliku dane: zawsze zwraca to co jest

potoki Proces potomny dziedziczy deskryptory, dziedziczy więc także deskryptory potoków! Standardowy schemat komunikacji z procesem potomnym: utwórz potok(i); wywołaj fork(); pozamykaj nieużywane deskryptory; korzystaj z potoków do komunikacji fork() fd[0] fd[1] fd[0] fd[1] fd[1] fd[0] fd[0] fd[1]

Przykład: popen() #include <sddio.h> #define READ 0 #define WRITE 1 #define tst(a,b) (mode == READ? (b) : (a)) int popen(char *cmd, int mode) { int p[2]; int popen_pid; if (pipe(p) < 0) return(null); if ((popen_pid = fork()) == 0) { /* proces potomny */ close(tst(p[write], p[read]); close(tst(0, 1)); /* 0 - stdin 1 - stdout */ dup(tst(p[read], p[write])); close(tst(p[read], p[write])); execl( /bin/sh, sh, -c, cmd, 0); exit(1); } if (popen_pid == -1) return(null); close(tst(p[read], p[write])); return(tst(p[write], p[read]); } /* proces macierzysty */

Przykład: popen2() #define READ 0 execl("/bin/sh", "sh", "-c", #define WRITE 1 command, NULL); pid_t popen2(const char *command, perror("execl"); int *infp, int *outfp) { exit(1); int p_stdin[2], p_stdout[2]; } /* pid==0 */ pid_t pid; if (pipe(p_stdin)!= 0 if (infp == NULL) pipe(p_stdout)!= 0) close(p_stdin[write]); return -1; else *infp = p_stdin[write]; if ((pid = fork())<0) if (outfp == NULL) return pid; close(p_stdout[read]); else if (pid == 0) { else *outfp = p_stdout[read]; close(p_stdin[write]); close(p_stdin[read]); dup2(p_stdin[read], READ); close(p_stdout[write]); close(p_stdout[read]); return pid; dup2(p_stdout[write], WRITE); }

Przykład: shell ls grep abc wc Tworzymy dwa potoki, trzy procesy: int fds1[2], fds2[2]; pipe(fds1); pipe(fds2) if (fork()==0) { /* ls */ ls: fds1[1] grep: fds1[0] wc: fds2[1] close(fds2[0]); close(fds2[1]); close(fds1[0]); dup2(fds1[1],1 ); close(fds1[1]); execlp( ls, ls,0); } if (fork()==0) /* grep */ { close(fds1[1]); close(fds2[0]); dup2(fds1[0],0); close(fds1[0]); dup2(fds2[1],1); close(fds2[1]); execlp( grep, grep, abc, 0); } if (fork()==0) /* wc */ { close(fds1[0]); close(fds1[1]); close( fds2[1]); dup2(fds2[0],0); close(fds2[0]); execlp( wc, wc, 0); } fds2[0]

FIFO Kolejki FIFO named pipes - potoki nazwane Identyfikowane przez pliki specjalne "widoczne" w syst. plików, Semantyka read/write identyczna jak dla potoków tworzonych przez pipe() Inny sposób tworzenia i otwierania Główna różnica w stosunku do pipe() - mogą używać procesy niespokrewnione np. proces serwisowy i jego klient Wywodzą się z SYSV, nie ma (?) w BSD Tworzenie: % mknod name p int mknod(char *pathname, int mode, int dev); mode: S_IFIFO prawa_dostępu int mkfifo(char *pathname, int mode); int unlink(char *pathname);

FIFO % mkfifo fifo1 % proga < fifo1 & % progb > fifo1 Otwieranie, zamykanie FIFO: open(), close() (fopen(), itd.) Jedna strona otwiera w trybie O_RD, druga O_WR (można też użyć O_RDWR) pierwsze (w sensie czasowym otwarcie) zawiesza się w oczekiwaniu na otwarcie drugiej strony: nie zawiesi się gdy O_RDWR uwaga na ewentualny deadlock gdy więcej niż jeden FIFO! Można wywołać open z flagą O_NDELAY

przykład FIFO client (int readfd, int writefd) { char buf[maxbuf]; int n; /* wczytaj nazwę pliku i zapisz do IPC */ if ( fgets (buf, MAXBUF, stdin ) == NULL ) err_sys ("client: filename read error "); n = strlen (buf); /* ignoruj newline */ if ( buf[n-1] == '\n' ) n-- ; if ( write (writefd, buf, n)!= n ) err_sys ("client: filename write error "); /* czytaj dane z IPC i prześlij na wyjście */ while ((n = read(readfd, buf, MAXBUF)) > 0) if (write(1, buf, n)!= n) /* 1=stdout */ err_sys ("client: data write error "); if ( n < 0 ) err_sys ("client: data read error "); }

przykład FIFO server (int readfd, int writefd) { char buf[maxbuf]; int n, fd; char errmesg[256], *sys_err_str(); /* wczytaj nazwę pliku z IPC */ if ((n = read(readfd, buf, MAXBUF)) <= 0) err_sys ("sever: filename read error "); buf[n] = '\0'; /* terminate filename */ if ((fd = open(buf, 0)) < 0) { /*wyślij komunikat o błędzie do klienta*/ sprintf(errmesg, "can't open, %s\n", sys_err_str()); strcat (buf, errmesg); n = strlen(buf); if (write ( writefd, buf, n)!= n ) err_sys("server: errmesg write error"); } else { /* czytaj dane i zapisz do IPC */ while ((n = read(fd, buf, MAXBUF)) > 0) if (write(writefd, buf, n)!= n) err_sys ("server: data write error"); if (n < 0) } err_sys("server: read error ");

przykład FIFO Plik fifo.h: #include <sys/types.h> #include <sys/stat.h> #include <sys/errno.h> #define FIFO1 "/tmp/fifo.1" #define FIFO2 "/tmp/fifo.2" #define PERMS 0666

przykład FIFO KLIENT - main int main(int argc, char**argv) { int readfd, writefd; /* otwarcie FIFO utworzonego przez serwer */ if ((writefd = open(fifo1, O_WR) < 0) err_sys("client: can't open wr fifo: %s", FIFO1); if ((readfd = open(fifo2, O_RD) < 0) err_sys("client: can't open rd fifo: %s", FIFO2); client (readfd, writefd); close (readfd); close (writefd); /* usuń FIFO */ if ( unlink( FIFO1 ) < 0 ) err_sys("client: can't unlink %s",fifo1); if (unlink( FIFO2 ) < 0 ) err_sys ("client: can't unlink %s",fifo2); exit (0); }

SERWER - main int main(int argc, char **argv) { int readfd, writefd; /* otwórz FIFO do odczytu i zapisu */ if ((mknod(fifo1, S_IFIFO PERMS, 0) < 0 && ( errno!= EEXIST )) err_sys ("can't create fifo: %s", FIFO1); if ((mknod(fifo2, S_IFIFO PERMS, 0) < 0 && ( errno!= EEXIST )) unlink ( FIFO1 ); err_sys ("can't create fifo: %s", FIFO1); } if (( readfd = open (FIFO1, O_RD) < 0) err_sys("server: can't open rd fifo: %s", FIFO1); if (( writefd = open (FIFO2, O_WR) < 0) err_sys("server: can't open wr fifo: %s", FIFO2); server (readfd, writefd); close (readfd); close (writefd); exit (0); {

SYSV IPC potok kolejka FIFO kolejka komunikatów semafory pamięć dzielona widoczność ------ścieżka klucz (key_t 32 bity) klucz klucz dostęp deskryptyor (int) deskryptyor identyfikator (int) identyfikator identyfikator Klucz -> identyfikator Klucz jak nazwa pliku, identyfikator jak deskryptor pliku Klucze identyfikujące obiekty IPC sa globalne i trwałe Generowanie kluczy: key_t ftok(char *pathname, char proj); Można też użyć klucza, który zapewni unikalny identyfikator: IPC_PRIVATE Funkcje systemowe: otwierające get sterujące control operacyjne operations msgget() msgctl() msgsnd() msgrcv() informacyjne: ipcrm(1), ipcs(1) semget() semctl() semop() shmget() shmctl() shmat() shmdt()

gjb@fox:~> ipcs ------ Shared Memory Segments -------key shmid owner perms bytes perms nsems perms used-bytes nattch status ------ Semaphore Arrays -------key semid owner ------ Message Queues -------key msqid owner messages root@fox:~# ipcs ------ Shared Memory Segments -------key shmid owner perms bytes nattch 0x0052ee79 0 pgsql8 600 169328640 2 0x0052f261 32769 pgsql83 600 38207488 4 0x0052e2c1 98306 postgres 600 168263680 1 ------ Semaphore Arrays -------key semid owner perms nsems 0x0052ee79 0 pgsql8 600 17 0x0052ee7a 32769 pgsql8 600 17 0x0052ee7b 65538 pgsql8 600 17 ------ Message Queues -------key root@fox:~# msqid owner perms used-bytes messages status

SYSV IPC funkcje...get() Tworzenie obiektów IPC: int msgget (key_t key, int msgflg); int semget (key_t key, int nsems, int semflg); int shmget (key_t key, int shmflg); klucz: IPC_CREATE IPC_CREATE IPC_EXCL wolny errno = ENOENT O.K. O.K. zajęty O.K. errno = EEXIST

SYSV IPC ipc_perm() Struktura ipc_perm jest wspólna dla wszystkich 3 typów obiektów IPC: struct ipc_perm { ushort uid; ushort gid; ushort cuid; ushort cgid; ushort mode; /* prawa dostępu */ ushort seq; key_t key; ipc_perm }; nagłówek: struct msqid_ds struct shmid_ds union semun dane

SYSV IPC funkcje sterujące int msgctl (int msqid, int cmd,.../* struct msqid_ds *buf */); int shmctl (int shmid, int cmd,.../* struct shmid_ds *buf */); int semctl(int semid, int semnum, int cmd,.../*union semun *arg */); cmd: IPC_STAT IPC_SET IPC_RMID - odczytaj nagłówek do bufora buf - zmodyfikuj dozwolone pola nagłówka - zwolnij obiekt

SYSV IPC Kolejki komunikatów int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg); int msgrcv (int msqid, const void *msgp, size_t msgsz, long msgtyp, int msgflg); Zwracają: msgsnd(): 0,-1; msgrcv(): liczba komunikatów Kolejka nie zawsze FIFO Typ może określać adresata Funkcje są domyślnie blokujące Gdy flaga IPC_NOWAIT nie blokują (zwracają -1 i errno <- EAGAIN (snd) lub ENOMSG (rcv) Odblokowanie gdy: pojawią się dane, lub usunięcie obiektu IPC lub sygnał struct msgbuf { long mtype;... }; msgrcv(): msgtyp = 0 msgtyp > 0 msgtyp < 0 pierwszy z kolejki pierwszy o zadanym typie typy o numerach niewiększych niż msgtyp

SYSV IPC Kolejki komunikatów int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg); int msgrcv (int msqid, const void *msgp, size_t msgsz, long msgtyp, int msgflg); struct msqid_ds { struct ipc_perm msg_perm; struct msg *msg_first; struct msg *msg_last; ushort msg_cbytes; /* ushort msg_gnum; /* ushort msg_gbytes; /* ushort msg_lspid; /* ushort msg_lrpid; /* } msqid msg_perm msg_first msg_last aktualna liczba bajtów w kolejce */ aktualna liczba komunikatow */ maks. liczba bajtów */ pid ostatniego msgsnd */ pid ostatniego msgrcv() */ typ długość dane typ długość dane typ (long) długość (>=0) dane

SYSV IPC Kolejki komunikatów msgq.h: #include < sys/types.h > #include < sys/ipc.h > #include < sys/msg.h > #include < sys/errno.h > extern int errno; #define MKEY1 1234L #define MKEY2 2345L #define PERMS 0666 SERWER: #include "mesgq.h" int main (int argc, char **argv) { int rdid, wrid; /* utwórz kolejkę */ if ((rdid=msgget(mkey1,perms IPC_CREAT))<0) err_sys("server : can't get queue1"); if ((wrid=msgget(mkey2,perms IPC_CREAT))<0) err_sys("server : can't get queue2" ); server (rdid, wrid); exit(0); }

SYSV IPC Kolejki komunikatów KLIENT - main #include "mesgq.h" int main (int argc, char **argv) { int reaid, wrid; /* otwórz kolejkę */ if ((wrid = msgget(mkey1, 0 )) < 0 ) err_sys ("client : can't get queue1" ); if ((rdid = msgget(mkey2, 1 )) < 0 ) err_sys ("client : can't get queue2" ); client (rdid, wrid); if (msgctl(rdid, IPC_RMID, (struct msqid_ds *)0 ) < 0 ) err_sys ("client: can't remove queue2" ); if (msgctl(wrid, IPC_RMID, (struct msqid_ds *)0 ) < 0 ) err_sys ("client: can't remove queue1" ); exit(0); }

SYSV IPC Semafory int semget (key_t key, int nsems, int semflg); int semop (int semid, struct sembuf *sops, size_t nsops); Operacje semaforowe są zawsze atomowe (wszystkie albo żadna) Jesli nie można wykonać to blokada struct semid_ds struct sem semid struct ipc_perm sem_perm struct sem *sem_base ushort sem_nsem time_t sem_otime time_t sem_ctime [0] [sem_nsem-1] [1] ushort semval short sempid ushort semncnt ushort semzcnt semval sempid semncnt semzcnt semval sempid semncnt semzcnt

SYSV IPC Semafory sem_op > 0 dodaj do semval - uwolnienie zasobu sem_op = 0 czekaj aż semval == 0 sem_op < 0 czekaj aż semval >= sem_op po czym odejmij - zajmowanie zasobu struct sembuf op_lock[2] = { 2, 0, 0, /* zaczekaj aż semafor nr 2 będzie zerem */ 2, 1, SEM_UNDO /* zwiększ ten semafor o 1 */ }; static struct sembuf op_unlock [1] = { 2, -1, SEM_UNDO, /* zmniejsz [2] */ } ; struct sembuf [0] sops ushort sem_num short sem_op short sem_flg [nsops-1] [1] sem_num sem_op sem_flg sem_num sem_op sem_flg

SYSV IPC Semafory int semctl(int semid, int semnum, int cmd,.../*union semun *arg*/); union semun { int val; /* GETVAL, SETVAL */ struct semid_ds *buff; /* IPC_STAT, IPC_SET */ ushort *array; /* GETALL, SETALL */ } arg; inne: /* IPC_RMID, GETPID, GETNCNT, GETZCNT */ Problemy zabicie procesu zajmującego semafor : Jak przywrócić właściwą wartość semafora? 1. obsługa sygnałów -> zwalnia blokadę ale SIGKILL 2. aktywne oczekiwanie (IPC_NOWAIT) i timeout 3. jądro uwalnia zajmowany semafor -> każdy proces posiada zmienną semadj SEM_UNDO: zmienia wartość nastawiajacą (semadj) przy kończeniu procesu semadj dodawana do wart semafora usuwanie semafora z systemu - pamiętać o usunięciu przed wywołaniem exit()

SYSV IPC pamięć dzielona int shmget (key_t key, int size, int shmflg); - zwraca shmid lub -1 void *shmat (int shmid, void *shmaddr, int shmflg); zwraca adres segmentu pamięci dzielonej lub -1 - adres określa system shmaddr == 0 shmaddr!= 0 && shmflg & SHM_RND - zaokrąglony adres dowiązania (mod SHMLBA) shmaddr!= 0 &&!(shmflg & SHM_RND) - adres dowiązania shmflg - SHM_RDONLY int shmdt (void *shmaddr); zwraca 0 lub -1 int shmctl (int shmid, int cmd,.../* struct shmid_ds *buf */); cmd: IPC_STAT, SHM_LOCK, IPC_SET, SHM_UNLOCK, IPC_RMID struct shmid_ds { struct ipc_perm struct anon_map int ushort ushort ushort ushort time_t time_t time_t }; shm_perm; *shm_amp; shm_segsz; shm_lpid; shm_cpid; shm_nattch; shm_cnattch; shm_atime; shm_dtime; shm_ctime; /* /* /* /* /* wskaźnik do str. kernela */ rozmiar segmentu */ pid ostatniego shmop */ pid twórcy */ liczba procesów dołączonych */

Pamięć wirtualna - VM

Założenia Pamięć wirtualna, przypomnienie: Strony (pages), ramki (frames w pamięci fizycznej) Założenia: Separacja przestrzeni adresowych Jednolitość przestrzeni adresowej (ten sam schemat dla każdego procesu) Ochrona obszarów: wykrycie odwołania do nielegalnego adresu, wykrycie nielegalnego odwołania (np. zapis do text, itp) Uruchamiamy programy o przestrzeni adresowej większej od dostępnego RAM Na raz w pamięci obecne są procesy o sumarycznej zajętości większej od dostępnego RAM Wspólne segmenty (text) mogą być wspóldzielone Procesy mogą współdzielić pamięć danych (IPC shmem)

Mechanizmy sprzętowe VM Schemat ogólny Uproszczony schemat procesorów Intel