Documente Academic
Documente Profesional
Documente Cultură
(1 2) PDU IntroducereProcese
(1 2) PDU IntroducereProcese
distribuita
1. Introducere
20132014
Scurta introducere
SISTEMUL DE OPERARE
UNIX
UNIX: Istoric
Anii 60
1969
1973
UNIX: Istoric
1976
UNIX
Version
7
Moment important in
dezvoltarea sistemelor UNIX
(devenit UNIX V6); prima
versiune general disponibila in
afara laboratoarelor AT&T.
Suplimentar, oferea
uneltele de dezvoltare
minimale pentru a suporta
activitatile de programare..
5/19/2014
UNIX: fundamente
Manipularea fisierelor
Toate fisierele sunt vazute ca simple secvente de
octeti. Fisierele si directoarele au o organizare
ierarhica, arborescenta.
Directoarele sunt vazute ca fisiere speciale, cu
un continut bine definit.
Un director contine informatiile necesare pentru
a mapa numele de fisier pe valoarea unui INod.
Numele de cale este utilizat pentru a facilita
accesul la informatii: este o secventa de nume,
intrari de director, separate prin caracterul /.
5/19/2014
UNIX: fundamente
Manipularea fisierelor
Un nume de cale absolut incepe totdeauna cu un caracter /:
Cautarea unui fisier se raporteaza totdeauna la radacina
sistemului de fisiere
Chiar si radacina este o notiune relativa. Aplicatiile au
posibilitatea de a modifica, temporar, intelesul radacinii, prin apelul
chroot ().
Un nume de cale relativ este un nume de cale care nu este
absolut! Punctul de pornire in rezolvarea numelor de cale relative
este reprezentat de directorul curent (de lucru).
Exista doua intrari speciale, legaturi fizice cu un inteles bine definit,
pentru a usura navigarea in arborele de directoare: . (self) si ..
(parent)
5/19/2014
UNIX: fundamente
Procese si semnale
Un proces UNIX nu este decat un program in curs
de executie. Procesele sunt identificate printr-o serie
de valori, printre care valoarea (unica) PID.
Procesele sunt create printr-un mecanism unic:
fork (), la dispozitia procesului parinte.
Semnalele ofera un mecanism de baza pentru
comunicarea intre procese; acestea sunt utilizate de
regula pentru semnalarea unor situatii exceptionale
in executia proceselor.
5/19/2014
UNIX: fundamente
Interpretorul de comenzi
Interpretorul de comenzi (shell) ofera un mediu
de baza pentru executia comenzilor utilizator.
Sistemul de operare ofera posibilitatea de alegere
si schimbare a shell-ului, pe baza
cerintelor/necesitatilor utilizatorilor.
Utilizatorii au posibilitatea de a porni aplicatii
(comenzi) atat intr-o maniera sincrona cat si intr-o
maniera asincrona.
5/19/2014
10
Structura programelor
Argumente in linia de comanda
Sintaxa functiei main ():
int main (int argc, char *argv [])
argc numarul de argumente in linia de comanda, incluzand numele programului curent;
argv tabloul tuturor argumentelor in linia de comanda.
A sample code
#include <stdio.h>
int main (int argc, char* argv[]) {
printf (Primul argument: numele programului ((%s)).\n, argv[0]);
if (argc > 1) {
/* Exista argumente in linia de comanda... */
int i;
printf (Argumentele, in ordinea specificarii lor:\n);
for (i = 1; i < argc; i++)
printf ( Arg(%2d): %s\n, i, argv[i]);
}
return 0 ;
}
11
Structura programelor
Argumente in linia de comanda
Exista doua categorii majore de argumente:
Optiuni
Argumente ordinare (e.g. File names)
Pentru a parcurge linia de comanda se pot
utiliza biblioteci predefinite, cum ar fi:
getopt
argp
12
Structura programelor
Argumente in linia de comanda
Conventii simple pentru numirea optiunilor:
-OPT (optiuni simple, unde OPT este un
singur caracter; e.g. -h)
--OPTION (optiuni lungi, unde OPTION
este un sir de caractere; e.g. --help).
Optiunile, atat simple cat si lungi, pot fi
urmate de zero sau mai multe argumente
(de regula, 0 sau 1 argument).
13
Structura programelor
2. Informatii de mediu
Aceste informatii sunt specificate prin perechi de
forma NAME=VALUE
Interpretorul de comenzi ofera mijloacele pentru acces
rapid la informatiile de mediu, prin maparea acestora
pe variabile (de mediu)
Mecanismul de definire a unor variabile noi depinde de
shell-ul utilizat. E.g.
VARIABILA=VALOARE
export VARIABILA
Operatia export este utilizata pentru a transforma
variabila shell intr-o variabila de mediu.
14
Structura programelor
2. Informatii de mediu
Functii necesare accesarii variabilelor de mediu:
#include <stdlib.h>
char *getenv (const char *)
int setenv (const char *, const char *, int replace)
int unsetenv (const char *)
Obs. Functia putenv () este invechita. Aceasta ofera
facilitati combinate pentru adaugare/stergere de
informatii de mediu.
15
Structura programelor
2. Informatii de mediu
Alternativ, aplicatiile pot utiliza informatii globale
extern char **environ
Pentru a accesa informatiile de mediu
#include <stdio.h>
extern char** environ;
int main () {
char** myVar;
for (myVar = environ; *myVar != NULL; myVar++)
printf (%s\n, *myVar);
return 0;
}
Structura programelor
3. Tema 1!
Construiti o aplicatie envprint simpla care:
Cu un argument l sau --list listeaza toate informatiile de mediu.
Cu un argument -n sau --name listeaza doar numele variabilelor
de mediu
Cu un argument s VAL sau --search VAL listeaza acele intrari care
contin SIRUL precizat ca VALOARE
Cu un argument r EXPR sau --regex EXPR listeaza acele intari
care se potrivesc cu expresia regulata precizata! (optional, doar
pentru Informatica Aplicata)
Fara nicio optiune, listeaza valorile tuturor variabilelor de mediu
existente)
Ofera posibilitatea de combinare a efectului actiunilor precizate.
17
Unelte
Compilatorul
Compilatorul tipic este cc sau versiunea GNU a acestuia, gcc:
Compilare simpla (genereaza executabilul a.out):
gcc c fisier_sursa.c
Compilare
gcc fisiere_sursa.c fisiere.o o fisier_executabil
Adaugare informatii de depanare:
gcc g
Diferite directive de compilare
(alternativa pentru #define )
gcc D NUME
gcc D NUME=val
18
Unelte
Utilitarul make
Make este o unealta (eficienta) pentru intretinerea
aplicatiilor.
Cu make, diferite sarcini legate de dezvoltarea si
intretinerea aplicatiilor pot fi automatizate.
Unelte
Utilitarul make. Un exemplu simplu.
De regula, fisierul se numeste makefile :
clean:
rm -f *.o reciprocal
Executia make main va crea tinta main, insa doar dupa verificarea si recrearea tintelor de
care aceasta depinde: main.o, secondary.o.
Ca efect secundar, este creat fisierul main
20
Unelte
Editorul
emacs, ca un editor text simplu, ofera un mediu de
baza pentru crearea si dezvoltarea de aplicatii C/UNIX.
The manual
Paginile de manual (prin utilitarul man) ofera suficiente
informatii programatorilor C pentru: functii de
biblioteca, apeluri sistem.
Utilitarul info poate fi utilizat pentru informatii
suplimentare sau pentru a suplini informatiile lipsa
man. E.g. info libc
21
Procese
SISTEMUL DE OPERARE
UNIX
Notiunea de proces
Un proces este un program aflat in curs
de executie
Procesele sunt insotite, de-a lungul
existentei, de o serie de informatii
importante (identificatori):
PID process ID
PPID parent process ID
GID group process ID
Real si effective user ID
23
Indentificatorii proceselor
Identificatorii proceselor
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main () {
printf (Identificatorul procesului curent
este [%d] , (int)getpid()) ;
printf (Identificatorul procesului parinte
este [%d], (int) getppid()) ;
return 0;
}
25
Identificatorii proceselor
Grupuri de procese
Pe langa identificarea simpla, este oferita
facilitatea de grupare a proceselor.
De exemplu, procesele create intr-un shell fac parte din
grupul acestuia: toate aceste procese pot fi controlate
prin intermediul procesului creator
Identificatorii proceselor
#include <signal.h>
int main () {
register int i ;
setpgrp () ;
for (i=0; i < 10; i++) {
if (fork() == 0) {
if (i & 1) setpgrp () ;
printf (PID=%d GID=%d\n, getpid(),
getpgrp()) ;
pause () ;
}
kill (0, SIGINT) ;
}
27
Identificatorii proceselor
28
Identificatorii proceselor
Identificatorii proceselor
Rezultatul executiei:
Daca EUID este un superuser, vor fi resetate atat
RUID cat si EUID
Altfel este resetat EUID la valoarea newUID, doar
daca newUID = RUID sau daca newUID este egal
cu valoarea setata in tabela proceselor (cand bitul
setuid este setat)
Identificatorii proceselor
#include <fcntl.h>
int main () {
int uid, euid, fda, fdb;
uid = getuid () ;
euid = geteuid () ;
printf (euid: %d, uid: %d\n, euid, uid) ;
fda = open (fisier_user_a, O_RDONLY) ;
fdb = open (fisier_user_b, O_RDONLY) ;
printf (Fisier a: %d, fisier b: %d\n, fda, fdb) ;
setuid (uid) ;
printf (Dupa setuid(%d):\n euid: %d, uid: %d\n, uid, geteuid(), getuid()) ;
fda = open (fisier_user_a, O_RDONLY) ;
fdb = open (fisier_user_b, O_RDONLY) ;
printf (Fisier a: %d, fisier b: %d\n, fda, fdb) ;
setuid (euid) ;
printf (Dupa setuid(%d):\n euid: %d, uid: %d\n, uid, geteuid(), getuid()) ;
return 0 ;
}
31
Identificatorii proceselor
Pentru exemplul anterior, se presupune ca
executabilul este detinut de utilizatorul B,
are bitul setuid fixat si toti utilizatorii au
permisiunea de a-l executa.
De asemenea, pentru cele doua fisiere se
presupune existenta permisiunii de citire.
Diferite programe sistem se bazeaza pe
mecanismul setuid pentru o functionare
corecta:
SISTEMUL DE OPERARE
UNIX
Crearea proceselor
Mecanismul system
Functia system () ofera cel mai simplu
mecanism de creare a proceselor si executie a
programelor
Acesta se bazeaza pe optiunea c a
interpretorului de comenzi.
Tehnic, functia system() va creea spatiul
necesar pentru executia unui shell, in care se
executa comanda specificata.
Rezultatul returnat este codul de eroare
returnat de comanda precizata, valoarea 127
daca shell-ul nu poate fi executat, sau valoarea
-1.
34
Crearea proceselor
#include <stdlib.h>
int main () {
int retValue ;
retValue = system (ps elf) ;
if (WIFEXITED(retValue))
printf (Status: %d\n, WEXITSTATUS(retValue)) ;
if (WIFSIGNALED(retValue))
printf (Status: %d\n, WTERMSIG(retValue)) ;
return WEXITSTATUS(retValue) ;
}
Observatie: pe durata executiei apelului system(), tratarea
semnalelor este alterata: SIGINT, SIGQUIT sunt ignorate (in
aplicatia parinte) iar SIGCHLD este blocat.
35
Mecanismul fork-exec
Apelul fork () ofera spatiul necesar pentru executia unui alt
program.
Apelurile din familia exec sunt folosite pentru a incarca un alt
program in spatiul nou creat.
if (fork () == 0) {
In urma unui apel exec... reusit noul program este incarcat in spatiul
procesului curent. Informatiile care definesc contextul procesului
curent sunt astfel inlocuite cu informatiile noului program.
Linia exec (EXIT_FAILURE) ; este accesibila doar daca apelul exec
nu este realizat cu succes. Aceasta linie previne ca procesul copil sa
aiba acces intamplator la informatiile procesului parinte.
36
Mecanismul fork-exec
Apelurile exec
Apelurile exec
execl ()
Apelul execl () are urmatoarea sintaxa
int execl (char *FILE, char *ARG0, , 0) ;
39
Apelul execl ()
if (fork () == 0) {
/* Preparations */
execl (/bin/ls, ls, -l, 0) ;
exit (EXIT_FAILURE) ;
}
pid = wait (&status) ;
Apelul wait realizat in procesul parinte va recupera informatia
de stare rezultata dupa executia programului precizat (aici ls).
Primul argument folosit precizeaza totdeauna fisierul, in timp ce
al doilea este numele in memorie al programului (corespunzand
cu argv[0] identificat prin functia main ())
40
Apelul execl ()
41
Executia programelor
Executia programelor modifica complet continutul memoriei in cazul
unui apel exec reusit.
Urmatoarele informatii raman insa nemodificate:
1.
2.
3.
4.
5.
6.
7.
PID si PPID; SID si GID; real UID si GID, file UID si GID; daca setUID sau
setGID sunt setati pentru acest program, valorile UID si GID efective vor
fi modificate corespunzator.
Alarme in asteptare;
Directorul curent si directorul radacina;
Masca de creare a fisierelor;
Masca semnalelor si semnalele in asteptare; Semnalele ignorate in parinte
raman ignorate si in copil; semnalele tratate revin insa la tratamentul
implicit.
Timpul procesor asociat;
Descriptorii de fisiere (mai putin atunci cand fisierele sunt deschise cu
flag-ul FD_CLOEXEC)
42
Apelurile exec
execv ()
Apelul execv () are urmatoarea sintaxa
int execv (char *FILE, char *ARGV[]) ;
Apelul execv () precizeaza lista de argumente intro maniera consistenta cu functia main(). Tabloul
ARGV se va incheia de regula cu o intrare nula
(valoarea 0 sau NULL) pentru a indica sfarsitul listei
de argumente.
Este forma dinamica de executie a unui program,
utilizabila atunci cand numarul de argumente in linia
de comanda este variabil
43
Apelul execv ()
/* Prepare argv array */
if (fork () == 0) {
/* Preparations */
execv (/bin/ls, argv) ;
exit (EXIT_FAILURE) ;
}
pid = wait (&status) ;
Apelul wait realizat in procesul parinte va recupera
informatia de stare rezultata dupa executia programului precizat
(aici ls).
Primul argument folosit precizeaza totdeauna fisierul, in timp ce
prima intrare din tabloul argv (obligatorie) reprezinta numele in
memorie al programului (corespunzand cu argv[0] identificat
prin functia main ())
44
Apelul execv ()
45
Terminarea proceselor
Terminarea proceselor
Terminarea proceselor
Asteptarea terminarii
Procesul parinte are la dispozitie un mecanism
simplu de sincronizare cu terminarea unui
proces copil: mecanismul wait.
pid_t wait (int *) ;
Terminarea proceselor
Asteptarea terminarii
Apelurile din familia wait (wait4, wait4,
waitpid) ofera posibilitatea de verificare
simpla, in locul suspendarii activitatii, prin
setarea optiunii WNOHANG.
Utilizarea optiunii WNOHANG ofera
posibilitatea eliminarii asincrone a proceselor:
Procesul parinte verifica periodic starea proceselor
copil si colecteaza informatiile de stare legate de
cele care eventual si-au terminat activitatea:
wait3 (&status, WNOHANG, NULL) ;
Pregatirea executiei
50