Differences

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

Link to this comparison view

so:laboratoare:laborator-11 [2016/05/11 23:32]
elena.sandulescu [Exercițiul 2 - epoll (2p)]
so:laboratoare:laborator-11 [2022/05/19 16:54] (current)
liza_elena.babu [Înainte de laborator: Feedback]
Line 1: Line 1:
 ====== Laborator 11 - Operații IO avansate - Linux ====== ====== Laborator 11 - Operații IO avansate - Linux ======
- 
-===== Materiale Ajutătoare ===== 
- 
-  * [[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab11-slides.pdf | lab11-slides.pdf]] 
-  * [[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab11-refcard.pdf | lab11-refcard.pdf]] 
  
  
Line 10: Line 5:
  
   * TLPI - Chapter 63, Alternative I/O models   * TLPI - Chapter 63, Alternative I/O models
 +
 +===== Link-uri către secțiuni utile =====
 +==== Linux ====
 +
 +  * [[#​linux_-_multiplexarea_io|Linux - multiplexarea I/O]]
 +    * [[#​select|select]]
 +    * [[#​poll|poll]]
 +    * [[#​epoll|epoll]]
 +  * [[#​linux_-_generalizarea_multiplexarii|Linux - generalizarea multiplexării]]
 +    * [[#​eventfd|eventfd]]
 +    * [[#​signalfd|signalfd]]
 +  * [[#​linux_-_operatii_asincrone|Linux - operații asincrone]]
 +  * [[#​zero-copy_io|Zero-copy I/O]]
 +  * [[#​vectored_io|Vectored I/O]]
 +
 +<​hidden>​
 +===== Înainte de laborator: Feedback =====
 +
 +Pentru a îmbunătăți cursul de SO, componentele sale și modul de desfășurare,​ ne sunt foarte utile opiniile voastre. Pentru aceasta, vă rugăm să accesați și completați formularul de feedback de pe site-ul acs.curs.pub.ro. Trebuie să fiți autentificați și înrolați în cadrul cursului.
 +
 +Formularul este anonim și este activ în perioada 11 mai 2020 - 22 mai 2020. Rezultatele vor fi vizibile în cadrul echipei cursului doar după încheierea sesiunii. Este accesibil la link-ul “Formular feedback” a paginii principale a cursului de SO al seriei voastre pe acs.curs.pub.ro. Nu este în meta-cursul disponibil tuturor seriilor.
 +
 +Vă invităm să evaluați activitatea echipei de SO și să precizați punctele tari și punctele slabe și sugestiile voastre de îmbunătățire a disciplinei. Feedback-ul vostru ne ajută să creștem calitatea materiei în anii următori și să îmbunătățim disciplinele pe care le veți face în continuare.
 +
 +Vom publica la începutul semestrului viitor analiza feedback-ului vostru.
 +
 +Ne interesează în special:
 +
 +  * Ce nu v-a plăcut și ce credeți că nu a mers bine?
 +  * De ce nu v-a plăcut și de ce credeți că nu a mers bine?
 +  * Ce ar trebuie să facem ca lucrurile să fie plăcute și să meargă bine?
 +</​hidden>​
 =====  Linux - multiplexarea I/O ===== =====  Linux - multiplexarea I/O =====
  
Line 56: Line 83:
  
 Dezavantaje:​ Dezavantaje:​
-    * lungimea ​setul de descriptori este definită cu ajutorul lui FD_SETSIZE, și implicit are valoarea ​64;+    * lungimea ​setului ​de descriptori este definită cu ajutorul lui ''​FD_SETSIZE''​, și implicit are valoarea ​1024;
     * este necesar ca seturile de descriptori să fie reconstruite la fiecare apel ''​select'';​     * este necesar ca seturile de descriptori să fie reconstruite la fiecare apel ''​select'';​
     * la apariția unui eveniment pe unul dintre descriptori,​ toți descriptorii puși în set înainte de ''​select''​ trebuie testați pentru a vedea pe care dintre ei a apărut evenimentul;​     * la apariția unui eveniment pe unul dintre descriptori,​ toți descriptorii puși în set înainte de ''​select''​ trebuie testați pentru a vedea pe care dintre ei a apărut evenimentul;​
Line 290: Line 317:
     epoll_wait(epfd,​ &​ret_ev,​ 1, -1);     epoll_wait(epfd,​ &​ret_ev,​ 1, -1);
    
-    if ((rev_ev.data.fd == listenfd && ((ret_ev.events & EPOLLIN) != 0)) {+    if ((ret_ev.data.fd == listenfd&& ((ret_ev.events & EPOLLIN) != 0)) {
         /* TODO ... handle new connection */         /* TODO ... handle new connection */
     }     }
-    else if ((rev_ev.data.fd == STDIN_FILENO &&+    else if ((ret_ev.data.fd == STDIN_FILENO&&
                     ((ret_ev.events & EPOLLIN) != 0)) {                     ((ret_ev.events & EPOLLIN) != 0)) {
         /* TODO ... read user data from standard input */         /* TODO ... read user data from standard input */
Line 310: Line 337:
  
 Pentru a asigura în Linux posibilitatea așteptării de evenimente multiple s-a definit interfața ''​eventfd''​. Cu ajutorul acestei interfețe și combinat cu interfețele de multiplexare I/O existente, kernel-ul poate notifica o aplicație utilizator de orice tip de eveniment. Pentru a asigura în Linux posibilitatea așteptării de evenimente multiple s-a definit interfața ''​eventfd''​. Cu ajutorul acestei interfețe și combinat cu interfețele de multiplexare I/O existente, kernel-ul poate notifica o aplicație utilizator de orice tip de eveniment.
- 
-Interfața ''​eventfd''​ este prezentă în nucleul Linux începând cu versiunea 2.6.22 și este suportată de către glibc începând cu versiunea 2.8. 
  
 Interfața ''​eventfd''​ permite unificarea mecanismelor de notificare ale kernel-ului într-un descriptor de fișier care va fi folosit de utilizator. Interfața ''​eventfd''​ permite unificarea mecanismelor de notificare ale kernel-ului într-un descriptor de fișier care va fi folosit de utilizator.
Line 426: Line 451:
 ==== Linux AIO ==== ==== Linux AIO ====
  
-Standardul ''​POSIX.1b''​ definește ​un nou set de operații I/O care pot reduce semnificativ timpul pe care o aplicație îl petrece așteptând pentru I/O. Noile funcții permit unui program să inițieze una sau mai multe operații de I/O și să-și continue lucrul normal în timp ce operațiile de I/O sunt executate în paralel. ​+Începând cu versiunea 2.5.32, kernelul Linux expune ​un set de operații I/O care pot reduce semnificativ timpul pe care o aplicație îl petrece așteptând pentru I/O. Noile funcții permit unui program să inițieze una sau mai multe operații de I/O și să-și continue lucrul normal în timp ce operațiile de I/O sunt executate în paralel. ​
  
 Această funcționalitate este disponibilă dacă se instalează biblioteca ''​libaio'':​ <code bash> Această funcționalitate este disponibilă dacă se instalează biblioteca ''​libaio'':​ <code bash>
Line 436: Line 461:
 </​code>​ </​code>​
  
-Totodată, programul care folosește acest API trebuie să includă fișierul header ''​[[http://​www.koders.com/c/fid4725E35EA2BE17467E3BB724D74D9FA6A471BFE7.aspx | libaio.h]]''​ și să link-eze biblioteca ''​libaio''​. Toate funcțiile și structurile de care vom vorbi în continuare se pot găsi în acest fișier header. Dacă ați instalat pachetul, fișierul se găsește în ''/​usr/​include/​libaio.h''​.+Totodată, programul care folosește acest API trebuie să includă fișierul header ''​[[http://​libaio.sourcearchive.com/documentation/0.3.109-1ubuntu1/​libaio_8h_source.html ​| libaio.h]]''​ și să link-eze biblioteca ''​libaio''​. Toate funcțiile și structurile de care vom vorbi în continuare se pot găsi în acest fișier header. Dacă ați instalat pachetul, fișierul se găsește în ''/​usr/​include/​libaio.h''​.
  
 ====Structuri de bază Linux AIO==== ====Structuri de bază Linux AIO====
  
-Structura ''​iocb''​ folosită pentru încapsularea unei operații asincrone. Structura este definită în header-ul ''​[[http://​www.koders.com/c/fid4725E35EA2BE17467E3BB724D74D9FA6A471BFE7.aspx | libaio.h]]''​.+Structura ''​iocb''​ folosită pentru încapsularea unei operații asincrone. Structura este definită în header-ul ''​[[http://​libaio.sourcearchive.com/documentation/0.3.109-1ubuntu1/​libaio_8h_source.html ​| libaio.h]]''​.
 <code c> <code c>
 struct iocb { struct iocb {
Line 502: Line 527:
  
  
- ​Pentru folosirea acesteia o aplicație va include ''​[[http://​www.koders.com/c/fid4725E35EA2BE17467E3BB724D74D9FA6A471BFE7.aspx | libaio.h]]''​. Un exemplu de inițializare a acestei structuri este:+ ​Pentru folosirea acesteia o aplicație va include ''​[[http://​libaio.sourcearchive.com/documentation/0.3.109-1ubuntu1/​libaio_8h_source.html ​| libaio.h]]''​. Un exemplu de inițializare a acestei structuri este:
 <code c> <code c>
         #include <​libaio.h>​         #include <​libaio.h>​
Line 647: Line 672:
 int efd; int efd;
    
-/creare event cu valoare inițială 0, fără flaguri speciale+/creare event cu valoare inițială 0, fără flaguri speciale ​*/
 efd = eventfd(0, 0); efd = eventfd(0, 0);
    
Line 674: Line 699:
 Este un apel de sistem ce permite transferul de date între 2 descriptori de fișier, dintre care cel puțin unul este pipe. Avantajul este că nu se folosește un buffer (byte array) în userspace. ​ Este un apel de sistem ce permite transferul de date între 2 descriptori de fișier, dintre care cel puțin unul este pipe. Avantajul este că nu se folosește un buffer (byte array) în userspace. ​
 <code c> <code c>
-#define _GNU_SOURCE /trebuie definit pentru că splice este o extensie nespecificată de standardele POSIX/​SYSV/​BSD/​etc.+#define _GNU_SOURCE /trebuie definit pentru că splice este o extensie nespecificată de standardele POSIX/​SYSV/​BSD/​etc. ​*/
  
 #include <​fcntl.h>​ #include <​fcntl.h>​
Line 702: Line 727:
 size_t count = 4096; size_t count = 4096;
    
-/... deschideri fișiere, creare pipe+/... deschideri fișiere, creare pipe */
    
 splice(file1,​ &​offset,​ pipe, NULL, count, 0); splice(file1,​ &​offset,​ pipe, NULL, count, 0);
Line 772: Line 797:
 } }
 </​code>​ </​code>​
-===== Exercițiul 0 - Joc interactiv (2p) ===== 
  
-  * Detalii desfășurare [[http://​ocw.cs.pub.ro/​courses/​so/​meta/​notare#​joc_interactiv|joc]]. +===== Exerciții ​=====
- +
-===== Linux (9p) ===== +
- +
-În rezolvarea laboratorului folosiți arhiva de sarcini [[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab11-tasks.zip | lab11-tasks.zip]]+
  
 <note important>​ <note important>​
-Acest laborator se desfășoară în echipeO echipă este formată din 2 studenți. În cazul în care numărul de studenți prezenți este impar, o singură echipă va avea dreptul de a avea 3 studenți.+În cadrul laboratoarelor vom folosi repository-ul de git al materiei SO - https://​github.com/​systems-cs-pub-ro/​so. Va trebui sa clonați repository-ul pe masinile virtuale folosind comanda: ''​git clone https://​github.com/​systems-cs-pub-ro/​so''​. Dacă doriți să descărcați repositoryul în altă locație, folosiți comanda ''​git clone https://​github.com/​systems-cs-pub-ro/​so ${target}''​.
  
-Discutați exercițiile școlaborați pe parcursul întregului laboratorHave fun! :-)+Pentru a actualiza repository-ul,​ folosiți comanda ''​git pull origin master''​ din interiorul directorului în care se află repository-ul. Recomandarea este să îl actualizați cât mai frecvent, înainte să începeți lucrul, pentru a vă asigura că aveți versiunea cea mai recentăÎn cazul în care gitul detectează conflicte la nivelul vreunui fişier, folosiți următoarele comenzi pentru a vă păstra modificările: 
 +<​code>​ 
 +git stash 
 +git pull origin master 
 +git stash pop 
 +</​code>​ 
 + 
 +Pentru mai multe informații despre folosirea utilitarului git, urmați ghidul de la https://​gitimmersion.com.
 </​note>​ </​note>​
  
-==== Exercițiul 1 - poll (1p) ====+==== Linux ==== 
 + 
 +=== Exercițiul 1 - poll ===
  
 Intrați în directorul ''​1-pollpipe''​. Parcurgeți fișierul ''​poll.c''​ pentru a vedea un exemplu de folosire al funcției ''​poll''​. Intrați în directorul ''​1-pollpipe''​. Parcurgeți fișierul ''​poll.c''​ pentru a vedea un exemplu de folosire al funcției ''​poll''​.
Line 805: Line 834:
  
  
-==== Exercițiul 2 - epoll (2p) ====+=== Exercițiul 2 - epoll ===
  
 Intrați în directorul ''​2-epollpipe''​ și parcurgeți fișierul ''​epoll.c''​. Considerând cerința de la exercițiul anterior, în loc de ''​poll''​ folosiți ''​epoll''​. Intrați în directorul ''​2-epollpipe''​ și parcurgeți fișierul ''​epoll.c''​. Considerând cerința de la exercițiul anterior, în loc de ''​poll''​ folosiți ''​epoll''​.
  
-În partea de inițializare realizați următoare operații:+În partea de inițializare realizați următoarele ​operații:
   * Inițializați,​ înainte de ciclul ''​for'',​ handle-ul de epoll folosing ''​epoll_create''​.   * Inițializați,​ înainte de ciclul ''​for'',​ handle-ul de epoll folosing ''​epoll_create''​.
   * Adăugați câte un eveniment pentru fiecare pipe (folosind variabila ''​ev''​) folosind ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_ADD''​.   * Adăugați câte un eveniment pentru fiecare pipe (folosind variabila ''​ev''​) folosind ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_ADD''​.
Line 822: Line 851:
   * Eliminați pipe-ul din multiplexor (folosind ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_DEL''​) și închideți-l folosind ''​close''​.   * Eliminați pipe-ul din multiplexor (folosind ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_DEL''​) și închideți-l folosind ''​close''​.
   * Incremenetați valoarea variabilei ''​recv_msgs''​.   * Incremenetați valoarea variabilei ''​recv_msgs''​.
-==== Exercițiul 3 - eventfd ​(2p) ====+ 
 +=== Exercițiul 3 - eventfd ===
  
 Pornind de la codul scris pentru execițiul anterior, notificați serverul de terminarea unui client utilizând ''​eventfd''​. Clientul transmite mesaje către server și, când dorește să închidă comunicația,​ va trimite un mesaj pe canalul de control reprezentat de ''​eventfd''​. Acum, ''​epoll''​ este folosit pentru a demultiplexa atât descriptorii de pipe, cât și descriptorul de ''​eventfd''​. Pornind de la codul scris pentru execițiul anterior, notificați serverul de terminarea unui client utilizând ''​eventfd''​. Clientul transmite mesaje către server și, când dorește să închidă comunicația,​ va trimite un mesaj pe canalul de control reprezentat de ''​eventfd''​. Acum, ''​epoll''​ este folosit pentru a demultiplexa atât descriptorii de pipe, cât și descriptorul de ''​eventfd''​.
Line 835: Line 865:
 Dacă descriptorul întors în urma ''​epoll_wait''​ este descriptorul de ''​eventfd'',​ atunci veți citi ''​64''​ de biți de pe acest descriptor (folosind ''​read''​). Dacă primii 32 biți sunt valoarea descrisă de macro-ul ''​MAGIC_EXIT'',​ atunci **scoate** capătul pipe-ului corespunzător din ''​epoll''​ și închide acel capăt (adică folosește ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_DEL''​ și apoi ''​close''​). Pentru a extrage ultimii 32 de biți din mesajul de ''​64''​ de biți primit pe descriptorul de ''​eventfd'',​ reprezentând indexul clientului, folosiți funcția ''​get_index''​ definită local în program. Dacă descriptorul întors în urma ''​epoll_wait''​ este descriptorul de ''​eventfd'',​ atunci veți citi ''​64''​ de biți de pe acest descriptor (folosind ''​read''​). Dacă primii 32 biți sunt valoarea descrisă de macro-ul ''​MAGIC_EXIT'',​ atunci **scoate** capătul pipe-ului corespunzător din ''​epoll''​ și închide acel capăt (adică folosește ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_DEL''​ și apoi ''​close''​). Pentru a extrage ultimii 32 de biți din mesajul de ''​64''​ de biți primit pe descriptorul de ''​eventfd'',​ reprezentând indexul clientului, folosiți funcția ''​get_index''​ definită local în program.
       ​       ​
-==== Exercițiul 4 - async I/O (KAIO) ​(2p) ====+=== Exercițiul 4 - async I/O (KAIO) ===
  
 Intrați în directorul ''​4-kaio''​ și parcurgeți fișierul ''​kaio.c''​. Completați zonele lipsă pentru a programa scrierea a 4 fișiere cu numele date de variabila ''​files''​. Intrați în directorul ''​4-kaio''​ și parcurgeți fișierul ''​kaio.c''​. Completați zonele lipsă pentru a programa scrierea a 4 fișiere cu numele date de variabila ''​files''​.
Line 843: Line 873:
 Parcurgeți secțiunea [[#​linux_aio|Linux AIO]] și consultați exemplul lui [[http://​www.xmailserver.org/​eventfd-aio-test.c | Davide Libenzi]]. Urmăriți comentariile cu // TODO 1 // Parcurgeți secțiunea [[#​linux_aio|Linux AIO]] și consultați exemplul lui [[http://​www.xmailserver.org/​eventfd-aio-test.c | Davide Libenzi]]. Urmăriți comentariile cu // TODO 1 //
  
-Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune ​8192 octeți create în ''/​tmp''​. ​+Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune ​''​BUFSIZ'' ​octeți create în ''/​tmp''​. ​
  
 **Atenţie!** În cazul în care, la compilare, header-ul '​libaio'​ nu este găsit rulaţi <code bash> **Atenţie!** În cazul în care, la compilare, header-ul '​libaio'​ nu este găsit rulaţi <code bash>
Line 850: Line 880:
  
  
-==== Exercițiul 5 - async I/O (KAIO) ​(2p) ====+=== Exercițiul 5 - async I/O (KAIO) ===
  
  ​Folosiți ''​eventfd''​ pentru așteptarea operațiilor asincrone. Porniți de la codul scris pentru execițiul anterior.  ​Folosiți ''​eventfd''​ pentru așteptarea operațiilor asincrone. Porniți de la codul scris pentru execițiul anterior.
Line 859: Line 889:
 Parcurgeți secțiunea [[#​linux_aio|Linux AIO]] și urmăriți comentariile cu // TODO 2 //. Consultați exemplul lui [[http://​www.xmailserver.org/​eventfd-aio-test.c | Davide Libenzi]]. ​ Parcurgeți secțiunea [[#​linux_aio|Linux AIO]] și urmăriți comentariile cu // TODO 2 //. Consultați exemplul lui [[http://​www.xmailserver.org/​eventfd-aio-test.c | Davide Libenzi]]. ​
  
-Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune 8192 octeți create în ''/​tmp''​.  +Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune 8192 octeți create în ''/​tmp''​. 
-===== BONUS =====+ 
 +==== BONUS ====
  
-  - **(1 so karma)** ​''​signalfd''​+  - ''​signalfd''​
      * Modificați codul de la exercițiul 2 pentru a permite notificarea de terminare a clienților bazată pe semnale.      * Modificați codul de la exercițiul 2 pentru a permite notificarea de terminare a clienților bazată pe semnale.
      * Server-ul:      * Server-ul:
Line 870: Line 901:
        * Consultați secțiunea [[#​signalfd|signalfd]]        * Consultați secțiunea [[#​signalfd|signalfd]]
        * [[ http://​linux.die.net/​man/​2/​signalfd | man signalfd ]]        * [[ http://​linux.die.net/​man/​2/​signalfd | man signalfd ]]
-===== Soluții ===== 
  
-[[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab11-sol.zip | Soluţii laborator 11]]  
so/laboratoare/laborator-11.1462998736.txt.gz · Last modified: 2016/05/11 23:32 by elena.sandulescu
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