Sunteți pe pagina 1din 50

Programare concurenta si

distribuita
1. Introducere
20132014

Scurta introducere

SISTEMUL DE OPERARE
UNIX

UNIX: Istoric

Anii 60

Proiectul MULTICS, cu participarea MIT,


AT&T Bell Labs si General Electric.

1969

Prima versiune a sistemului de operare,


initial dezvoltat de K.Thompson si D.Ritchie,
bazat pe activitatea anterioara la proiectul
MULTICS.

1973

Limbajul C, conceput pentru a suporta


redesignul sistemului de operare. Noua
dezvoltarea a sistemului UNIX este inalt
portabila, usor de mentinut.
5/19/2014

UNIX: Istoric
1976

UNIX
Version
7

Moment important in
dezvoltarea sistemelor UNIX
(devenit UNIX V6); prima
versiune general disponibila in
afara laboratoarelor AT&T.

Punctul de start oficial pentru


numeroase versiuni comerciale
ale sistemului de operare; directii
principale AT&T, BSD sau
XENIX.
5/19/2014

UNIX: principii de baza


Primele sisteme de operare UNIX
erau destul de mici pentru a fi usor
de inteles;

Utiliza algoritmi simpli (si


rapizi) in locul unor
metode sofisticate.

Dezvoltarea initiala se bazeaza pe


un design simplu;

Dezvoltarea este extrem


de flexibila.

Sistemele UNIX erau, de la inceput,


sisteme interactive, oferind un
mediu minimal pentru activitatile de
programare.
5/19/2014

Suplimentar, oferea
uneltele de dezvoltare
minimale pentru a suporta
activitatile de programare..

UNIX: principii de baza


UNIX systems are highly portable, mainly
because most of the kernel was (re)written in
a high level programming language

The C programming language was


developed for this specific task.

UNIX systems were, from the beginning,


systems with time sharing, with a standard
user interface, kept as simple as possible.

The file systems have a tree-like hierarchy of


directories.

Process scheduling is typically based on a


simple algorithm, with priorities.

5/19/2014

All files (including special files) are


seen as simple sequences of bytes,
while basic I/O operations have a
simplistic, quite basic, syntax.

However, additional mechanisms like


virtual memory, swapping, paging on
demand, provided important help to
the activity of process management.

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;
}

Obs. Aplicatiile UNIX ofera, de fapt, un al treilea argument al functiei


main(), al carui inteles este legat de variabila environ :
int main (int argc, char *argv [], char **envp)
16

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.

Un make file contine o serie de tinte, cu un set de


reguli asociate pentru fiecare tinta si eventuale
dependinte necesare pentru a construi aceste tinte
Dependintele pot fi, de asemenea, tinte
19

Unelte
Utilitarul make. Un exemplu simplu.
De regula, fisierul se numeste makefile :

main: main.o secondary.o


gcc $(CFLAGS) -o main main.o secondary.o
main.o: main.c secondary.h
gcc $(CFLAGS) -c main.c
secondary.o: secondary.c secondary.h
gcc $(CFLAGS) -c secondary.c

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

Identitatea proceselor se bazeaza pe


valorile PID si PPID, prin care se
implementeaza ierarhia de baza a
proceselor.
PID is PPID sunt valori intregi, pe 16 biti, de
tip pid_t (sys/types.h)
Procesul init se afla la baza structurii
arborescente (PID=1, PPID=0).
Apelurile sistem getpid() si getppid() ofera
informatii directe legate de acesti
identificatori.
24

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

Procesele inrudite in acest mod sunt identificate


prin valoarea GID, depozitata in tabela
proceselor.
Un copil al unui proces se gaseste, automat, in grupul
procesului parinte.

Orice proces, de-a lungul activitatii sale, este


capabil sa initieze un grup propriu.
26

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

In plus fata de PID, nucleul asociaza doi identificatori


suplimentari proceselor:
Identificatorul UTILIZATOR REAL acesta este
utilizatorul care este responsabil cu procesul curent!
Identificatorul UTILIZATOR EFECTIV

Identificatorul de utilizator efectiv este utilizat pentru


A desemna proprietatea asupra fisierelor nou create
A verifica permisiunile de acces la fisiere
A verifica permisiunile de transmitere a semnalelor

Procesele au posibilitatea de a modifica valoarea


identificatorului de utilizator efectiv prin
Setarea permisiunii speciale setuid
Utilizarea explicita a apelului sistem setuid()

28

Identificatorii proceselor

Permisiunea speciala setuid


Un program setuid este un fisier executabil
pentru care bitul setuid corespunzator a fost
setat.
Aceasta posibilitate este oferita de comanda
chmod:
chmod +s fisier

La executia unui program setuid, este fixata


valoarea utilizator efectiv la valoarea
utilizatorului care detine acest fisier.
29

Identificatorii proceselor

Apelul sistem setuid ():


Sintaxa
setuid (newUID) ;

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)

Observatie: in general aceasta valoare este


pastrata de-a lungul executiei proceselor
copil.
30

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:

Utilitarul mkdir sau login folosesc acest


mecanism.
32

Crearea si Executia programelor

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) {

/* Prepare new program execution */


execl (PRG, PRG, ARG, 0) ;
exit (EXIT_FAILURE) ;
}

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

Mecanismul fork-exec ofera suportul


necesar pentru executia programelor.
Mecanismul presupune urmatorii pasi:
1. Creeaza spatiu pentru un proces nou, initial
identic cu procesul parinte;
2. Pregateste incarcarea unui program diferit in
spatiul de adrese;
3. Incarca un program diferit in spatiul de
adrese.
37

Apelurile exec

Apelurile exec
execl ()
Apelul execl () are urmatoarea sintaxa
int execl (char *FILE, char *ARG0, , 0) ;

Apelul execl () precizeaza lista de argumente in linia


de comanda explicit, chiar in apelul realizat.Valoarea
0 (NULL) este necesara pentru a marca sfarsitul
listei de argumente.
Este forma directa de executie a unui program,
utilizabila atunci cand numarul de argumente in linia
de comanda este prestabilit

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 ()

Urmatoarele variante sunt disponibile pentru apelul


execl ():
execle (char *FILE, char *ARG, , 0, char *ENVP []) ;
Aceasta varianta permite specificarea unei liste de
informatii de mediu (vezi argumentul optional al functiei
main()). Informatiile suplimentare oferite permit rularea
programului intr-un mediu modificat.
execlp () ;
Aceasta varianta este similara cu apelul original. Diferenta
este data de faptul ca este realizata o cautare automata in
lista de directoare precizata in PATH, atunci cand FILE nu
este precizat printr-un nume de cale absolut.

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)

Suplimentar, un apel exec realizat cu succes modifica access time


pentru programul incarcat prin acest apel.

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 ()

Urmatoarele variante sunt disponibile pentru apelul


execv ():
execve (char *FILE, char *ARGV[], char *ENVP []) ;
Aceasta varianta permite specificarea unei liste de
informatii de mediu (vezi argumentul optional al functiei
main()). Informatiile suplimentare oferite permit rularea
programului intr-un mediu modificat.
execvp (char *FILE, char *ARGV[]) ;
Aceasta varianta este similara cu apelul original. Diferenta
este data de faptul ca este realizata o cautare automata in
lista de directoare precizata in PATH, atunci cand FILE nu
este precizat printr-un nume de cale absolut.

45

Terminarea proceselor

Terminarea proceselor

Terminarea proceselor are loc, de regula,


printr-un apel exit ().
Un proces in curs de terminare devine proces
zombie, eliberand resursele ocupate si contextul
procesului, mai putin intrarea din tabela de
procese.

Apelul exit () are loc fie explicit, fie implicit.


exit (stare);

Valoarea de stare returnata poate fi culeasa


printr-un apel wait (wait, waitpid) de catre
procesul parinte pentru a determina modul in
care procesul copil si-a terminat executia.
47

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 *) ;

Mecanismul wait intoarce PID-ul procesului


care si-a incheiat executia, si depoziteaza
informatia de stare
Mecanismul este activat prin semnalul
SIGCLD (SIGCHLD)
Mecanismul de baza wait este completat cu
apeluri wait3, wait4 si waitpid.
48

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) ;

Mecanismul de colectare a informatiilor poate fi


completat cu ajutorul semnalului SIGCLD.
49

Pregatirea executiei

In pregatirea executiei aplicatiile UNIX


pot avea in vedere actualizarea
informatiilor care nu se modifica in urma
apelului exec
Directorul curent si directorul radacina;
Informatii legate de fisierele deschise;
Masca de creare a fisierelor;

50

S-ar putea să vă placă și