Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so:curs:fs-ops [2020/02/17 10:15]
razvan.deaconescu created
so:curs:fs-ops [2020/05/24 20:36] (current)
dragos_florin.costea [Descriptori de fișier pentru procesele daemon]
Line 16: Line 16:
     * [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​SO_Curs-02.pdf | Curs 02 - Interfața sistemului de fișiere (PDF)]]     * [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​SO_Curs-02.pdf | Curs 02 - Interfața sistemului de fișiere (PDF)]]
  
-===== Demo-uri ===== +  * Slide-uri CA [[https://www.slideshare.net/alexandruradovici/​sisteme-de-operare-sistemul-de-fisiere|slideshare]]
- +
-Pentru parcurgerea demo-urilor,​ folosim ​[[http://elf.cs.pub.ro/so/res/​cursuri/​curs-02-demo.zip|arhiva aferentă]]. Demo-urile rulează pe Linux. Descărcăm arhiva folosind comanda<​code bash> +
-wget http://​elf.cs.pub.ro/​so/​res/​cursuri/​curs-02-demo.zip +
-</​code>​ și apoi decomprimăm arhiva<​code bash> +
-unzip curs-02-demo.zip +
-</​code>​ și accesăm directorul rezultat în urma decomprimării<​code bash> +
-cd curs-02-demo/​ +
-</​code>​ +
- +
-Acum putem parcurge secțiunile cu demo-uri de mai jos. +
- +
-==== Tabela de descriptori de fișier a unui proces ==== +
- +
-Pentru a afișa tabela de descriptor de fișier a procesului shell current (PID-ul său este reținut în construcția ''​$$''​),​ folosim comanda<​code bash> +
-lsof -a -d 0-1023 -p $$ +
-</​code>​ +
- +
-Ce referă descriptorii 0, 1, 2? +
- +
-<spoiler Răspuns>​ +
-Descriptorii 0, 1 și 2 reprezintă,​ respectiv, intrarea standard (//standard input//, //stdin//), ieșirea standard (//standard output//, //stdout//) și ieșirea de eroare standard (//standard error//, //​stderr//​). Toți cei trei descriptori referă, de obicei, un dispozitiv de tip terminal (de forma ''/​dev/​pts/​0''​);​ adică atunci când se citesc sau se scriu informații de la/către descriptori,​ acestea sunt preluate de la terminal +
-</​spoiler>​ +
- +
-De ce (pe unele sisteme) descriptorul 0 este marcat ''​0r''​ (adică read-only)? +
- +
-<spoiler Răspuns>​ +
-Descriptorul 0 referă intrarea standard (//standard input//). Întrucât ​de la intrarea standard doar se **citesc** informații,​ are sens să fie deschis doar pentru citire (adică //read-only//). +
-</​spoiler>​ +
- +
-<​note>​ +
-Pe anumite sisteme descriptorul este marcat cu ''​0u''​ adică este read-write; dar, în mod practic, este folosit doar pentru citire. +
-</​note>​ +
-==== Descriptori de fișier pentru procesele daemon ==== +
- +
-Vrem să investigăm descriptorii de fișiere pentru procesele daemon din sistem. Pentru început vrem să aflăm procesele daemon din sistem; procesele daemon au ca proces părinte procesul ''​init''​ (procesul cu PID-ul ''​1''​) și vom folosi comanda de mai jos pentru a le afla:<​code bash> +
-ps --ppid 1 +
-</​code>​ +
- +
-Pentru unul dintre procesele daemon descoperite prin rularea comenzii anterioare, afișăm tabela de descriptori (e nevoie de drept de ''​root''​) folosind comanda ''​lsof'':<​code bash> +
-sudo lsof -a -d 0-1023 -p $PID +
-</​code>​ +
- +
-Mai sus, construcția ''​$PID''​ referă PID-ul procesului daemon inspectat. +
- +
-Ce referă descriptorii 0, 1, 2? De ce? +
- +
-<spoiler Răspuns>​ +
-Descriptorii 0, 1, 2, aferenți intrării, ieșirii și ieșirii de eroare standar, referă ''/​dev/​null''​. +
- +
-Un proces daemon nu este atașat nici unui terminal. Nu există mod prin care utilizatorul poate comunica direct cu acesta prin intermediul intrării sau ieșirii standard, motiv pentru care acestea referă ''/​dev/​null'',​ "gaura neagră"​ a sistemului. +
-</​spoiler>​ +
- +
-Ce alți descriptori sunt folosiți? Ce referă acești descriptori?​ +
- +
-<spoiler Raspuns>​ +
-Sunt folosiți în continuare alți descriptori:​ 4, 5, 6 etc. Descriptorii proceselor daemon vor referi fișiere de jurnalizare (//log files//), sockeți Unix sau sockeți de rețea sau fișiere deschise pentru a fi prelucrate. Utilizatorul va comunica cu daemonii prin semnale, fișiere de configurare,​ sockeți și fișiere de jurnalizare. +
-</​spoiler>​ +
- +
-==== Descriptorii de fișier după redirectare ==== +
- +
-Vrem să vedem cum se modifică descriptorii de fișier în cazul redirectării. Pentru a putea vedea acest lucru vom rula o comandă de durată (''​sleep''​) și vom redirecta intrarea și ieșirea standard:<​code bash> +
-sleep 100 < /etc/passwd > f.txt +
-</​code>​ +
- +
-Pentru a investiga procesul ''​sleep''​ proaspăt pornit, trebuie să știm PID-ul său. Deschidem o altă consolă și aflăm PID-ul procesului ''​sleep''​ creat folosind comanda:<​code bash> +
-pidof sleep +
-</​code>​ +
- +
-Vom folosi construcția ''​$PID''​ referă PID-ul procesului ''​sleep''​ pe care-l investigăm. Ca și până acum, afișam tabela de descriptori de fișier a procesului folosind comanda:<​code bash> +
-lsof -a -o -d 0-1023 -p $PID +
-</​code>​ +
- +
-Ce referă acum descriptorul 0, respectiv 1? +
- +
-<spoiler Răspuns>​ +
-În urma redirectării intrării standard cu operatorul ''<'',​ descriptorul ''​0''​ referă acum fișierul ''/​etc/​passwd''​. La fel, în urma redirectării ieșirii standard cu operatorul ''>'',​ descriptorul ''​1''​ referă acum fișierul ''​f.txt''​. +
-</​spoiler>​ +
- +
-==== Modificarea cursorului de fișier ==== +
- +
-Vrem să urmărim modificarea cursorului de fișier (numit și //file pointer// sau //file offset//). Pentru aceasta vom folosi un program C în care, la cererea utilizatorului folosim apeluri care alterează cursorul de fișier: ''​write''​ și ''​lseek'',​ +
- +
-Pentru început intrăm în subdirectorul ''​c-file-ops/''​ din directorul cu demo-uri și urmărim fișierul ''​c-file-ops.c''​. Observăm că în program se deschide fișierul ''​f.txt''​ și apoi se scrie (folosind ''​write''​) și se parcurge fișierul (folosind ''​lseek''​). Fiecare operație este precedată de apăsarea tastei ENTER din parte utilizatorului. Compilăm programul folosind comanda<​code bash> +
-user@host:​~$ make +
-</​code>​ și obținem executabilul ''​c-file-ops''​. Rulăm executabilul ''​c-file-ops'':<​code bash> +
-./​c-file-ops +
-</​code>​ +
- +
-Pentru a urmări evoluția tabelei de descriptori și a cursorului de fișier, vom folosi comanda ''​lsof''​. Într-o altă consolă rulăm comanda<​code bash> +
-lsof -a -o -d 0-1023 -p $(pidof c-file-ops) +
-</​code>​ Pentru început sunt afișați doar descriptorii standard. +
- +
-Pentru a urmări evoluția tabelei de descriptori de fișier și a cursorului de fișier, vom folosi ''​ENTER''​ în consola în care am rulat executabilul ''​c-file-ops''​. Vom urmări evoluția programului în consola în care am rulat ''​lsof''​. +
- +
-<note tip> +
-Coloana ''​OFFSET''​ indică poziția cursorului de fișier. +
-</​note>​ +
- +
-Inițial cursorul de fișier are valoarea ''​0''​ întrucât a fost proaspăt deschis și trunchiat. La apăsarea tastei ''​ENTER''​ în prima consolă, care indică programul să facă o nouă acțiune, observăm modificarea cursorului de fișier în a doua consolă. +
- +
-Parcurgem întreg programul pentru a urmări evoluția completă a cursorului de fișier. +
- +
-La finalul rulării programului urmărim dimensiunea fișierului ''​f.txt'':<​code bash> +
-stat -c "​%s"​ f.txt +
-256 +
-</​code>​ Observăm că fișierul are dimensiunea de 256 octeți, atât cât a primit ca argument apelul ''​ftruncate''​. +
- +
-Ce efect are apelul ''​ftruncate''​ asupra cursorului de fișier? +
- +
-<spoiler Răspuns>​ +
-Apelul ''​ftruncate''​ modifică dimensiunea fișierului. Un fișier are un câmp de dimensiune alterat de comanda ''​ftruncate''​. Acest câmp este diferit de cursorul de fișier. Teoretic cursorul de fișier poate fi plasat dincolo de sfârșitul fișierului. Din acest motiv, apelul ''​ftruncate''​ nu are nici un efect asupra cursorului de fișier. +
- +
-Acest lucru este precizat și în [[http://​man7.org/​linux/​man-pages/​man2/​ftruncate.2.html#​DESCRIPTION|secțiunea DESCRIPTION a paginii de manual a apelului ftrunctate]]. +
-</​spoiler>​ +
- +
-==== Modificarea cursorului de fișier (Python) ==== +
- +
-Vrem să vedem cum este alterat cursorul de fișier în cazul unui program Python. Pentru aceasta, accesăm subdirectorul ''​py-file-ops/''​ din directorul cu demo-uri al cursului și parcurgem fișierul ''​py-file-ops.py''​. Observăm că structura este similară celei de la demo-ul anterior: se scriu date în fișier, se parcurge fișierul, se așteaptă apăsarea tastei ''​ENTER''​ din partea utilizatorului. +
- +
-Rulăm programul folosind comanda:<​code bash> +
-python py-file-ops.py +
-</​code>​ +
- +
-Pentru a urmări evoluția tabelei de descriptori și a cursorului de fișier, deschidem o altă consolă în care rulăm comanda<​code bash> +
-lsof -a -o -d 0-1023 -p $(pgrep -f py-file-ops) +
-</​code>​ Sunt afișați doar descriptorii standard pentru că încă nu a fost deschis fișierul. +
- +
-Pentru a deschide fișierul și a efectua oprații asupra sa, vom apăsa ''​ENTER''​ în consola în care am rulat programul ''​py-file-ops''​. Urmărim evoluția programului în consola în care ați rulat ''​lsof''​. +
- +
-<note tip> +
-Coloana ''​OFFSET''​ indică poziția cursorului de fișier. +
-</​note>​ +
- +
-Folosim de mai multe ori ''​ENTER''​ pentru a parcurge toți pașii din program și pentru a investiga evoluția cursorului de fișier. La fel ca la demo-ul anterior, fișierul va avea în final dimensiunea de ''​256''​ octeți:<​code bash> +
-stat -c "​%s"​ f.txt  +
-256 +
-</​code>​ +
- +
-De ce nu există tot timpul o corespondență între operațiile Python și modificarea cursorului de fișier? De exemplu, în cazul ''​f.read()'',​ deși trebuia să se incrementeze contorul cu ''​256''​ octeți, a fost incrementat cu ''​512''​. +
- +
-<spoiler Răspuns>​ +
-Python nu folosește direct apelurile oferite de sistemul ​de operare. Biblioteca standard Python oferă wrappere peste apelurile expuse de sistemul de operare și biblioteca standard C. Astfel, în cazul unui apel ''​f.read()''​ se realizează,​ în fundal, un transfer de ''​512''​ octeți și se bufferează pentru viitoare operații. +
-</​spoiler>​ +
- +
-Ce se întâmplă dacă nu se apelează ''​f.flush()''​ (după ciclul de scriere cu ''​f.write()''​)?​ +
- +
-<spoiler Răspuns>​ +
-Dacă nu se apelează ''​f.flush()''​ datele rămân în bufferele interne ale bibliotecii standard Python. Aceste date vor fi sincronizate (flushed) la un moment de timp ulterior: fie când se apelează ''​f.flush()'',​ fie când se închide fișierul, fie când se face o operație care impune sincronizarea datelor. +
-</​spoiler>​ +
-==== Buffered I/O vs. System-Level I/O ==== +
- +
-Ne propunem să investigăm diferențele dintre apelurile de tip buffered I/O și cele de tip system-level I/O. Intrăm în subdirectorul ''​buffered-system-io/''​ din directorul cu demo-uri ale cursului și urmărim fișierele ''​buffered.c''​ și ''​system.c''​. Observăm că operațiile efectuate sunt similare; diferă doar funcțiile folosite, unele de tip buffered I/O, altele de tip system-level I/O. +
- +
-Compilăm cele două programe folosind comanda:<​code bash> +
-make +
-</​code>​ +
- +
-Pentru a investiga apelurile de bibliotecă ale programului ''​buffered''​ executăm rapid pașii: +
-  - Într-o consolă rulăm programul ''​buffered'':<​code bash> +
-./​buffered +
-</​code>​ +
-  - Rapid, într-o altă consolă, urmărim **apelurile de bibliotecă** realizate de programul ''​buffered''​ folosind comanda:<​code bash> +
-ltrace -e putchar,​fputc -p $(pidof buffered) +
-</​code>​ +
- +
-Pentru a investiga **apelurile de sistem** ale programului ''​buffered''​ executăm rapid pașii: +
-  - Într-o consolă rulăm programul ''​buffered'':<​code bash> +
-./​buffered +
-</​code>​ +
-  - Rapid, într-o altă consolă, urmărim **apelurile de sistem** realizate de programul ''​buffered''​ folosind comanda:<​code bash> +
-strace -e write -p $(pidof buffered) +
-</​code>​ +
- +
-Care este numărul de apeluri de bibliotecă și numărul de apeluri de sistem realizate de programul ''​buffered''​ în cadrul buclelor ''​for''?​ +
- +
-<spoiler Răspuns>​ +
-Programul ''​buffered''​ realizează 10 apeluri de bibliotecă ''​putchar''​ și 20 apeluri de bibliotecă ''​putc'',​ conform celor două bucle ''​for''​. Întrucât folosește buffered I/O, se face flush/​sincronizare,​ adică se face apel de sistem doar dacă se ajunge la un caracter //newline// (''​\n''​) sau dacă se apelează ''​fflush()''​. Deci se vor face doar două apeluri de sistem: unul la apelul ''​printf("​\n"​);''​ și altul la apelul ''​fflush(f);''​. +
-</​spoiler>​ +
- +
-Realizați pașii de mai sus și pentru programul ''​system''​. Doar că pentru a detecta apelurile de bibliotecă realizate folosiți comanda<​code bash> +
-ltrace -e write -p $(pidof system) +
-</​code>​ +
- +
-Care este numărul de apeluri de bibliotecă și numărul de apeluri de sistem realizate de programul ''​system''?​ +
- +
-<spoiler Răspuns>​ +
-La fel ca programul ''​buffered'',​ programul ''​system''​ realizează tot 10 + 20 = 30 apeluri de bibliotecă,​ dar ''​write''​ în acest caz. Întrucât folosește system-level I/O fiecărui apel de bibliotecă îi corespunde un apel de sistem, deci vor fi tot 30 de apeluri de sistem. +
- +
-Întrucât apelurile de sistem sunt costisitoare,​ este recomandată folosirea buffered I/O. Dar, dacă este nevoie ca datele să fie sincronizate/​flush imediat ce au fost scrise, va trebui folosit system-level I/O. +
-</​spoiler>​ +
-==== Apelul dup și cursorul de fișier ==== +
- +
-Ne propunem să urmărim efectul apelului ''​dup()''​ asupra cursorului de fișier. Pentru aceasta accesăm subdirectorul ''​open-dup/''​ din directorul cu demo-uri a cursului și parcurgem fișierele ''​open.c''​ și ''​dup.c''​. În ambele fișiere se deschid doi descriptori de fișier (''​fd1''​ și ''​fd2''​):​ în cazul fișierului ''​open.c''​ descriptorul ''​fd2''​ este creat folosind apelul ''​open()'',​ iar în cazul fișierului ''​dup.c''​ descriptorul ''​fd2''​ este creat folosind apelul ''​dup()''​. +
- +
-Compilăm programele folosind comanda<​code bash> +
-make +
-</​code>​ și obținem executabilele ''​open''​ și ''​dup''​. +
- +
-Rulăm executabilul ''​open'':<​code bash> +
-./open +
-</​code>​ +
- +
-Pentru a urmări tabela de descriptori de fișier și cursorul de fișier pentru procesul creat, deschidem o altă consolă și rulăm comanda:<​code bash> +
-watch -d lsof -a -o -d 0-1023 -p $(pidof open) +
-</​code>​ +
- +
-În consola în care am rulat executabilul ''​open''​ folosim comanda ''​ENTER''​ pentru a parcurge pașii din program. Urmărim în a doua consolă evoluția tabelei de descriptori și a cursorului de fișier. +
- +
-<note tip> +
-Coloana ''​OFFSET''​ indică poziția cursorului de fișier. +
-</​note>​ +
- +
-Realizați aceeași pași pentru executabilul ''​dup''​. +
- +
-Ce diferențe apar la nivelul tabelei de descriptori de fișier și cursor de fișier între programul ''​open''​ și programul ''​dup''?​ +
- +
-<spoiler Răspuns>​ +
-Ambele apeluri creează o intrare nouă în tabela de descriptori de fișier. În cazul apelului ''​dup''​ intrarea nou creată este o clonă a celei vechi. Alterarea cursorului de fișier pentru descriptorul ''​fd1''​ este vizibilă pentru descriptorul ''​fd2''​. Cei doi descriptori referă aceeași structură, care conține același cursor de fișier. În cazul apelului ''​open''​ intrările sunt distincte, chiar dacă în final referă același fișier. Modificarea cursorului de fișier pentru descriptorul ''​fd1''​ nu afectează cursorul de fișier pentru descriptorul ''​fd2''​. +
-</​spoiler>​ +
-===== Link-uri recomandate ===== +
- +
-[[http://​www.ibm.com/​developerworks/​aix/​library/​au-lsof.html|Finding open files with lsof]] ====== Curs 02 - Interfața sistemului de fișiere ====== +
- +
-  * [[http://​prezi.com/​5-5ua6acyxv9/​so-curs-2/?​kw=view-5-5ua6acyxv9&​rc=ref-31844697 | Curs 02 - Interfața sistemului de fișiere (vizualizare Prezi)]] +
-  * [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​SO_Curs-02.pdf | Curs 02 - Interfața sistemului de fișiere (PDF)]] +
- +
-  * [[https://​docs.google.com/​document/​d/​1kH3Sg8OcW8oMUqsuG1jaicUxUze05vN_2wHaJix3W28/​edit?​usp=sharing|Notițe de curs]] +
- +
-  * Suport curs +
-    * Operating System Concepts Essentials +
-      * Capitolul 9 - File-System Interface +
-      * Capitolul 10, Secțiunea 10.1 - File-System Structure +
-    * Linux System Programming +
-      * Capitolul 2 (programatic) +
-    * Windows System Programming +
-      * Capitolul 2 (programatic) +
- +
-<​html>​ +
-  <​center>​ +
-    <iframe src="​https://​prezi.com/​embed/​5-5ua6acyxv9/?​bgcolor=ffffff&​amp;​lock_to_path=0&​amp;​autoplay=no&​amp;​autohide_ctrls=0&​amp;​features=undefined&​amp;​disabled_features=undefined"​ width="​550"​ height="​400"​ frameBorder="​0"></​iframe>​ +
-  </​center>​ +
-</​html>​+
  
 ===== Demo-uri ===== ===== Demo-uri =====
Line 308: Line 66:
  
 <spoiler Răspuns>​ <spoiler Răspuns>​
-Descriptorii 0, 1, 2, aferenți intrării, ieșirii și ieșirii de eroare ​standar, referă ''/​dev/​null''​.+Descriptorii 0, 1, 2, aferenți intrării, ieșirii și ieșirii de eroare ​standard, referă ''/​dev/​null''​.
  
 Un proces daemon nu este atașat nici unui terminal. Nu există mod prin care utilizatorul poate comunica direct cu acesta prin intermediul intrării sau ieșirii standard, motiv pentru care acestea referă ''/​dev/​null'',​ "gaura neagră"​ a sistemului. Un proces daemon nu este atașat nici unui terminal. Nu există mod prin care utilizatorul poate comunica direct cu acesta prin intermediul intrării sau ieșirii standard, motiv pentru care acestea referă ''/​dev/​null'',​ "gaura neagră"​ a sistemului.
Line 480: Line 238:
 Ambele apeluri creează o intrare nouă în tabela de descriptori de fișier. În cazul apelului ''​dup''​ intrarea nou creată este o clonă a celei vechi. Alterarea cursorului de fișier pentru descriptorul ''​fd1''​ este vizibilă pentru descriptorul ''​fd2''​. Cei doi descriptori referă aceeași structură, care conține același cursor de fișier. În cazul apelului ''​open''​ intrările sunt distincte, chiar dacă în final referă același fișier. Modificarea cursorului de fișier pentru descriptorul ''​fd1''​ nu afectează cursorul de fișier pentru descriptorul ''​fd2''​. Ambele apeluri creează o intrare nouă în tabela de descriptori de fișier. În cazul apelului ''​dup''​ intrarea nou creată este o clonă a celei vechi. Alterarea cursorului de fișier pentru descriptorul ''​fd1''​ este vizibilă pentru descriptorul ''​fd2''​. Cei doi descriptori referă aceeași structură, care conține același cursor de fișier. În cazul apelului ''​open''​ intrările sunt distincte, chiar dacă în final referă același fișier. Modificarea cursorului de fișier pentru descriptorul ''​fd1''​ nu afectează cursorul de fișier pentru descriptorul ''​fd2''​.
 </​spoiler>​ </​spoiler>​
- 
 ===== Link-uri recomandate ===== ===== Link-uri recomandate =====
  
-[[http://​www.ibm.com/​developerworks/​aix/​library/​au-lsof.html|Finding open files with lsof]] ​+[[http://​www.ibm.com/​developerworks/​aix/​library/​au-lsof.html|Finding open files with lsof]]
so/curs/fs-ops.1581927337.txt.gz · Last modified: 2020/02/17 10:15 by razvan.deaconescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0