This shows you the differences between two versions of the page.
so:laboratoare:laborator-11 [2015/05/18 00:57] laura.vasilescu [Exercițiul 4 - async I/O (KAIO) (3p)] |
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 echipe. O 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 și colaborați pe parcursul întregului laborator. Have 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 ==== |
- | - (**1 punct**) ''poll'' | + | |
- | * Intrați în directorul ''1-pollpipe''. | + | |
- | * Parcurgeți fișierul ''poll.c'' pentru a vedea un exemplu de folosire al funcției ''poll''. | + | |
- | * Programul creează folosind ''fork'' o aplicație de test pentru ''poll''. Aplicația folosește un server (părintele) și ''CLIENT_COUNT'' clienți (copiii) ce comunică prin pipe-uri anonime. | + | |
- | * Server-ul: | + | |
- | * construiește un vector de pipe-uri (în funcția ''main''); | + | |
- | * creează clienții; | + | |
- | * se blochează în așteptarea datelor de la clienți și tipărește datele primite; | + | |
- | * termină execuția după ce a primit date de la fiecare client; | + | |
- | * Clienții: | + | |
- | * așteaptă un număr aleator de secunde (mai mic decât 10); | + | |
- | * scriu în pipe-ul corespunzător un șir de ''MSG_SIZE'' caractere de forma ''<pid>:<caracter random>'' ('a' + random() % 30); | + | |
- | * scrierile și citirile în pipe-uri de până la PIPE_BUF octeți (4096 pe Linux) sunt atomice. | + | |
- | * Compilați și rulați programul. | + | |
- | * Pentru nelămuriri puteti consulta secțiunea [[#poll|poll]] și [[laborator-03#pipe-uri_anonime_in_linux|pipe-uri]] în Linux. | + | |
+ | === Exercițiul 1 - poll === | ||
- | ==== Exercițiul 2 - epoll (2p) ==== | + | Intrați în directorul ''1-pollpipe''. Parcurgeți fișierul ''poll.c'' pentru a vedea un exemplu de folosire al funcției ''poll''. |
- | - (**2 puncte**) ''epoll'' | + | |
- | * Intrați în directorul ''2-epollpipe''. | + | |
- | * 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: | + | |
- | * 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''. | + | |
- | * Câmpul ''events'' al variabilei ''ev'' îl veți inițializa la ''EPOLLIN''. | + | |
- | * Câmpul ''data.fd'' al variabilei ''ev'' îl veți inițializa la capătul de citire al pipelului. | + | |
- | * Închideți capătul de scriere al pipe-ului. | + | |
- | * În partea de așteptare realizați, în bucla ''while'' următoarele operații: | + | |
- | * Așteptați un eveniment folosind funcția ''epoll_wait''. | + | |
- | * Descriptorul indicat în structura întoarsă de ''epoll_wait'' (adică ''ev.data.fd'') este capătul de citire al pipe-ului. | + | |
- | * Din pipe citiți mesajul trimis de client, folosind ''read''. | + | |
- | * Închideți pipe-ul (folosind ''close'') și eliminați-l din multiplexor (folosind ''epoll_ctl'' cu opțiunea ''EPOLL_CTL_DEL''). | + | |
- | * Incremenetați valoarea variabilei ''recv_msgs''. | + | |
- | * **Hints**: | + | |
- | * Urmăriți comentariile marcate cu // TODO // | + | |
- | * Consultați secțiunea [[#epoll|epoll]] | + | |
+ | Programul creează folosind ''fork'' o aplicație de test pentru ''poll''. Aplicația folosește un server (părintele) și ''CLIENT_COUNT'' clienți (copiii) ce comunică prin pipe-uri anonime. | ||
- | ==== Exercițiul 3 - eventfd (2p) ==== | + | **Server-ul:** |
- | - (**2 puncte**) ''eventfd'' | + | * construiește un vector de pipe-uri (în funcția ''main''); |
- | * 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''. | + | * creează clienții; |
- | * Acum, ''epoll'' este folosit pentru a demultiplexa atât descriptorii de pipe, cât și descriptorul de ''eventfd''. | + | * se blochează în așteptarea datelor de la clienți și tipărește datele primite; |
- | * Decomentați în ''epoll.c'' linia cu <code c>#define USE_EVENTFD</code> | + | * termină execuția după ce a primit date de la fiecare client; |
- | * Clientul va realiza următoarele operații: | + | **Clienții:** |
- | * Va scrie mesaje în pipe-ul aferent. | + | * așteaptă un număr aleator de secunde (mai mic decât 10); |
- | * La sfârșit va genera un mesaj de notificare. Va folosi funcția ''set_event'' definită în program. | + | * scriu în pipe-ul corespunzător un șir de ''MSG_SIZE'' caractere de forma <code><pid>:<caracter random> ('a' + random() % 30)</code> |
- | * Mesajul de notificare este un număr pe 64 de biți organizat astfel: | + | * scrierile și citirile în pipe-uri de până la PIPE_BUF octeți (4096 pe Linux) sunt atomice. |
- | * Primii 32 de biți conțin valoarea definită de macro-ul ''MAGIC_EXIT''. | + | |
- | * Ultimii 32 de biți conțin indexul clientului. | + | |
- | * Serverul va realiza următoarele operații, suplimentar față de exercițiul anterior. | + | |
- | * Adaugă descriptorul de ''eventfd'' în ''epoll'' (cu eveniment de tipul ''EPOLLIN''). | + | |
- | * Așteaptă evenimente folosind ''epoll_wait'' (așa cum făcea și până acum). | + | |
- | * Apelul ''epoll_wait'' se întoarce când un descriptor din ''epoll'' are informații de citit. | + | |
- | * Descriptorul întors în urma ''epoll_wait'' (identificat de câmpul ''ev.data.fd'') poate fi descriptor de pipe sau poate fi descriptorul de ''eventfd''. | + | |
- | * 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. | + | |
- | * **Hints**: | + | |
- | * Consultați secțiunea [[#eventfd|eventfd]] | + | |
+ | Compilați și rulați programul. Pentru nelămuriri puteti consulta secțiunea [[#poll|poll]] și [[laborator-03#pipe-uri_anonime_in_linux|pipe-uri]] în Linux. | ||
- | ==== Exercițiul 4 - async I/O (KAIO) (2p) ==== | + | |
- | - (**3 puncte**) Asynchronous I/O (KAIO) | + | === Exercițiul 2 - epoll === |
- | * Intrați în directorul ''4-kaio''. | + | |
- | * Parcurgeți fișierul ''kaio.c''. | + | 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''. |
- | * Completați zonele lipsă pentru a programa scrierea a 4 fișiere cu numele date de variabila ''files''. | + | |
- | * Folosiți API-ul KAIO (io_setup, io_destroy, io_submit, io_getevents). | + | În partea de inițializare realizați următoarele operații: |
- | * Folosiți **doar** io_getevents pentru așteptarea încheierii operațiilor asincrone. | + | * Inițializați, înainte de ciclul ''for'', handle-ul de epoll folosing ''epoll_create''. |
- | * **Hints**: | + | * Adăugați câte un eveniment pentru fiecare pipe (folosind variabila ''ev'') folosind ''epoll_ctl'' cu opțiunea ''EPOLL_CTL_ADD''. |
- | * Parcurgeți secțiunea [[#linux_aio|Linux AIO]]. | + | * Câmpul ''events'' al variabilei ''ev'' îl veți inițializa la ''EPOLLIN''. |
- | * Consultați exemplul lui [[http://www.xmailserver.org/eventfd-aio-test.c | Davide Libenzi]]. | + | * Câmpul ''data.fd'' al variabilei ''ev'' îl veți inițializa la capătul de citire al pipelului. |
- | * Urmăriți comentariile cu // TODO 1 // | + | * Închideți capătul de scriere al pipe-ului. |
- | * Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune 8192 octeți create în ''/tmp''. | + | |
- | * **Atenţie!** În cazul în care, la compilare, header-ul 'libaio' nu este găsit rulaţi <code bash> | + | În partea de așteptare realizați, în bucla ''while'' următoarele operații: |
+ | * Așteptați un eveniment folosind funcția ''epoll_wait''. | ||
+ | * Descriptorul indicat în structura întoarsă de ''epoll_wait'' (adică ''ev.data.fd'') este capătul de citire al pipe-ului. | ||
+ | * Din pipe citiți mesajul trimis de client, folosind ''read''. | ||
+ | * 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''. | ||
+ | |||
+ | === 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''. | ||
+ | |||
+ | Decomentați în ''epoll.c'' linia cu <code c>#define USE_EVENTFD</code> | ||
+ | Clientul va scrie mesaje în pipe-ul aferent, iar la sfârșit va genera un mesaj de notificare. Acesta va folosi funcția ''set_event'' definită în program. Mesajul de notificare este un număr pe 64 de biți organizat astfel: | ||
+ | * Primii 32 de biți conțin valoarea definită de macro-ul ''MAGIC_EXIT''. | ||
+ | * Ultimii 32 de biți conțin indexul clientului. | ||
+ | |||
+ | Serverul va adăuga descriptorul de ''eventfd'' în ''epoll'' (cu eveniment de tipul ''EPOLLIN''). Evenimentele vor fi așteptate folosind ''epoll_wait'' (așa cum făcea și până acum). Apelul ''epoll_wait'' se întoarce când un descriptor din ''epoll'' are informații de citit. Descriptorul întors în urma ''epoll_wait'' (identificat de câmpul ''ev.data.fd'') poate fi descriptor de pipe sau poate fi descriptorul de ''eventfd''. | ||
+ | |||
+ | 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) === | ||
+ | |||
+ | 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''. | ||
+ | |||
+ | Folosiți API-ul KAIO (io_setup, io_destroy, io_submit, io_getevents). Folosiți **doar** io_getevents pentru așteptarea încheierii operațiilor asincrone. | ||
+ | |||
+ | 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 ''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> | ||
so$ sudo apt-get install libaio1 libaio-dev | so$ sudo apt-get install libaio1 libaio-dev | ||
</code> | </code> | ||
- | ==== Exercițiul 5 - async I/O (KAIO) (2p) ==== | + | === Exercițiul 5 - async I/O (KAIO) === |
- | - (**2 puncte**) Asynchronous I/O (KAIO) + eventfd | + | |
- | * Folosiți ''eventfd'' pentru așteptarea operațiilor asincrone. | + | Folosiți ''eventfd'' pentru așteptarea operațiilor asincrone. Porniți de la codul scris pentru execițiul anterior. |
- | * Porniți de la codul scris pentru execițiul anterior. | + | |
- | * Decomentați în ''kaio.c'' linia cu <code c>#define USE_EVENTFD</code> | + | Decomentați în ''kaio.c'' linia cu <code c>#define USE_EVENTFD</code> |
- | * La inițializarea structurilor ''iocb'', folosiți funcția ''io_set_eventfd'' pentru a activa folosirea ''eventfd'' | + | La inițializarea structurilor ''iocb'', folosiți funcția ''io_set_eventfd'' pentru a activa folosirea ''eventfd''. Completați funcția ''wait_aio'' pentru a aștepta terminarea operațiilor asincrone folosind ''eventfd''. |
- | * Completați funcția ''wait_aio'' pentru a aștepta terminarea operațiilor asincrone folosind ''eventfd'' | + | |
- | * **Hints**: | + | 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]]. | + | |
- | * Urmăriți comentariile cu // TODO 2 // | + | Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune 8192 octeți create în ''/tmp''. |
- | * 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''. | + | ==== 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 890: | 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]] |