close

Transkrypt

close
UXP – lato 2015, Grzegorz Blinowski
UXP1A
Unix – Programowanie i
Architektura
lato 2015
Grzegorz Blinowski
Instytut Informatyki
Politechniki Warszawskiej
UXP – lato 2015, 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 2015, Grzegorz Blinowski
Regulamin itp.
•
Inne
– Wolne czwartki: 4.06
– Wykładu nie będzie 23.04,
– Będzie wyznaczony termin zastępczy (pt 12-14 lub 14-16 sala 138)
– Kolokiwum I – po omówieniu mechanizmów IPC (9.04?)
– Kolokiwum II – po omówieniu całości materiału (28.05 - ?)
– Oceny, wpisy, poprawa 11.06 (ostatnie zajęcia)
– Projekt: start ok. 9.04, zaliczenie do 11.06
•
Wymagania
– Systemy operacyjne
– Dobra znajomość języka C
•
Materiały – dostępne na stronie http://www.ii.pw.edu.pl/~gjb
•
Kontakt: [email protected], tel PW: 222347184; konsultacje wt. 10-12
UXP – lato 2015, 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
•
•
•
•
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
(Wikimedia Commons)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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”
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
(Wikimedia Commons)
UXP – lato 2015, Grzegorz Blinowski
Cechy
•
•
Przenośność - źródła C + kilka % 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)
•
•
•
Wirtualny i rozproszony system plików
Wirtualny - w jednym drzewie wiele typów systemów plików
Rozproszony - obejmuje wiele maszyn w sieci
UXP – lato 2015, Grzegorz Blinowski
System procesów
UXP – lato 2015, Grzegorz Blinowski
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.
UXP – lato 2015, Grzegorz Blinowski
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()
UXP – lato 2015, Grzegorz Blinowski
Diagram stanów procesu (stary)
UXP – lato 2015, Grzegorz Blinowski
Diagram stanów procesu - Linux
•
TASK_RUNNING – w
trakcie wykonania lub
gotowy
•
INTERRUPTIBLE lub
UNINTERRUPTIBLE
– odp. SSLEEP
•
TASK_STOPPED
(nie pokazany –
SIGTSTP i inne)
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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()
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
Mapa pamięci procesu
UXP – lato 2015, Grzegorz Blinowski
Mapa pamięci procesu
• 2^32 lub 2^44 (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
UXP – lato 2015, Grzegorz Blinowski
API
#include <unistd.h>
– pid_t getpid(void);
– pid_t getppid(void);
UXP – lato 2015, Grzegorz Blinowski
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 */
UXP – lato 2015, Grzegorz Blinowski
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:
UXP – lato 2015, Grzegorz Blinowski
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 */
};
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
/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
UXP – lato 2015, Grzegorz Blinowski
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);
UXP – lato 2015, Grzegorz Blinowski
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”
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
fork(), wait(), exec()
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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 !
UXP – lato 2015, Grzegorz Blinowski
Ś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:~$
UXP – lato 2015, Grzegorz Blinowski
Ś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
UXP – lato 2015, Grzegorz Blinowski
Ś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:~$
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
Sygnały
•
Źródła sygnałów:
– Sam proces – 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”
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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ą)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
sygnały niezawodne
Sig_handler() {flag=1;}
. . .
Sig_handler() {flag=1;}
. . .
for (;;) {
for (;;) {
sigprocmask(
);
while (flag == 0)
while (flag == 0)
pause();
}
. . .
sigsuspend(mask);
}
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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()
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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 ...
UXP – lato 2015, Grzegorz Blinowski
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).
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
UXP – lato 2015, Grzegorz Blinowski
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()
}
UXP – lato 2015, Grzegorz Blinowski
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.
UXP – lato 2015, Grzegorz Blinowski
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ł)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
Klasy priorytetów
• Klasa określa algorytm szeregowania
• Klasa jest dziedziczona
• Nowy scheduler (tj. dla nowej klasy) może być
dostarczony jako zbiór dobrze określonych funkcji
kernela:
– np. CL_FORK,
CL_PREEMPT, CL_SLEEP, CL_STOP, CL_WAKEUP
– #define CL_PREEMPT(classfuncs, arg)\
(*(classfuncs)->p_clfuncs->cl_preempt)(arg)
– Takie rozwiązanie pozwala na wywołanie makra CL_* I przekazanie
odpowiedniej funkcji argumentu niezaleznie od klasy szeregowania
danego procesu
UXP – lato 2015, Grzegorz Blinowski
start systemu, init
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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);
UXP – lato 2015, Grzegorz Blinowski
System plików
UXP – lato 2015, Grzegorz Blinowski
System plików - podstawy
• Drzewo plików
• Korzeń drzewa: “File system root”, katalog aktualny “current dir”
• Typy plików: zwykłe, katalogi (d), sterowniki znakowe (c) i
blokowe (b), FIFO (p), sym-link (l), socket (s), inne
• Atrybuty plików:
– Nazwa:
• znaki dozwolone – wszystkie prócz \0 i /
• Niezalecane – znaki wzorce shella, spacja
– Właściciel, grupa
– prawa dostępu: owner (user), group, other; setuid, setgid,
sticky
– Daty-czasy: dostepu, modyfikacji, modyfikacji metryczki
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
API systemu plików
•
chmod, chown, close, creat, dup, dup2, fcntl,
link, lseek, open, read, stat, umask, write,
unlink, stat(5),
UXP – lato 2015, Grzegorz Blinowski
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ług 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)
UXP – lato 2015, Grzegorz Blinowski
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 */
UXP – lato 2015, Grzegorz Blinowski
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 */
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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*/
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
...
UXP – lato 2015, Grzegorz Blinowski
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);
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
•
...
UXP – lato 2015, Grzegorz Blinowski
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 ...
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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 katualną pozycję, “przewija” do wskazanej pozycji
UXP – lato 2015, Grzegorz Blinowski
Operacje na katalogach
#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;
}
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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 */
UXP – lato 2015, Grzegorz Blinowski
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.
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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);
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
Komunikacja międzyprocesowa
UXP – lato 2015, Grzegorz Blinowski
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)
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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]
UXP – lato 2015, Grzegorz Blinowski
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(p[READ], p[WRITE]);
return(tst(p[WRITE], p[READ]);
}
/* proces macierzysty */
UXP – lato 2015, Grzegorz Blinowski
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);
}
UXP – lato 2015, Grzegorz Blinowski
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]
UXP – lato 2015, Grzegorz Blinowski
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);
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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 ");
}
UXP – lato 2015, Grzegorz Blinowski
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 ");
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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);
}
UXP – lato 2015, Grzegorz Blinowski
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);
{
UXP – lato 2015, Grzegorz Blinowski
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()
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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|
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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);
}
UXP – lato 2015, Grzegorz Blinowski
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);
}
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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
UXP – lato 2015, Grzegorz Blinowski
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()
UXP – lato 2015, Grzegorz Blinowski
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 */

Podobne dokumenty