You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 22-networking/03.1-select-poll.md
+10-10Lines changed: 10 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -45,10 +45,10 @@ Les `fd_set` se manipulent exclusivement via quatre macros :
45
45
```cpp
46
46
fd_set fds;
47
47
48
-
FD_ZERO(&fds); // Initialise l'ensemble à vide (obligatoire)
49
-
FD_SET(fd, &fds); // Ajoute fd à l'ensemble
50
-
FD_CLR(fd, &fds); // Retire fd de l'ensemble
51
-
FD_ISSET(fd, &fds); // Teste si fd est dans l'ensemble (après select)
48
+
FD_ZERO(&fds); // Initialise l'ensemble à vide (obligatoire)
49
+
FD_SET(fd, &fds); // Ajoute fd à l'ensemble
50
+
FD_CLR(fd, &fds); // Retire fd de l'ensemble
51
+
FD_ISSET(fd, &fds); // Teste si fd est dans l'ensemble (après select)
52
52
```
53
53
54
54
> 🔥 **Piège critique** : `select`**modifie** les `fd_set` passés en paramètre. Après l'appel, seuls les descripteurs effectivement prêts restent dans l'ensemble. Il faut donc **reconstruire les ensembles à chaque itération** de la boucle événementielle.
@@ -218,12 +218,12 @@ La séparation `events` / `revents` est une amélioration majeure par rapport à
218
218
### Constantes d'événements
219
219
220
220
```cpp
221
-
POLLIN // Données disponibles en lecture
222
-
POLLOUT // Écriture possible sans blocage
223
-
POLLPRI // Données urgentes (out-of-band)
224
-
POLLERR // Erreur sur le descripteur (revents uniquement)
225
-
POLLHUP // Déconnexion du pair (revents uniquement)
`POLLERR`, `POLLHUP` et `POLLNVAL` sont toujours surveillés implicitement — inutile de les spécifier dans `events`, ils apparaissent dans `revents` si la condition se produit.
Copy file name to clipboardExpand all lines: 22-networking/03.2-epoll.md
+14-14Lines changed: 14 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -60,8 +60,8 @@ Crée une instance epoll et retourne un descripteur de fichier qui la représent
60
60
Le seul flag utile est `EPOLL_CLOEXEC`, qui positionne le flag close-on-exec pour éviter que le descripteur soit hérité par des processus fils créés avec `exec`. C'est une bonne pratique systématique :
En mode ET, le noyau ne vous notifie qu'**une seule fois** lors de la transition de « pas de données disponibles » à « données disponibles ». Si vous ne lisez pas toutes les données lors de cette notification, vous ne serez pas renotifié — même si des données restent dans le buffer — jusqu'à ce que de *nouvelles* données arrivent.
@@ -402,10 +402,10 @@ struct Connection {
402
402
// À l'accept d'une nouvelle connexion :
403
403
auto* conn = new Connection{.fd = client_fd};
404
404
405
-
epoll_event ev{};
406
-
ev.events = EPOLLIN;
407
-
ev.data.ptr = conn; // Le noyau retournera ce pointeur tel quel
> ⚠️ `data` est une **union** : `fd`, `ptr`, `u32` et `u64` partagent le même espace mémoire. Si vous utilisez `data.ptr`, vous ne pouvez pas simultanément lire `data.fd` — il faut stocker le descripteur dans votre structure `Connection`.
io_uring_smp_store_release(cq_head_ptr, head + 1);
@@ -331,23 +331,23 @@ En pratique, dimensionnez la CQ suffisamment grande pour ne jamais déborder dan
331
331
L'application prépare ses SQE, les pousse dans la SQ, puis appelle `io_uring_enter` pour notifier le noyau. C'est un appel système, mais un seul peut soumettre un lot arbitrairement grand de SQE — le coût est **amorti sur le nombre d'opérations**.
332
332
333
333
```
334
-
App: préparer SQE[0], SQE[1], SQE[2]
335
-
App: io_uring_enter(to_submit=3, min_complete=1) ← 1 seul appel système
334
+
App: préparer SQE[0], SQE[1], SQE[2]
335
+
App: io_uring_enter(to_submit=3, min_complete=1) ← 1 seul appel système
336
336
pour 3 opérations + attente
337
-
Kernel: exécute les 3 opérations
338
-
Kernel: dépose 2 CQE (2 sont terminées)
339
-
App: récolte les 2 CQE
337
+
Kernel: exécute les 3 opérations
338
+
Kernel: dépose 2 CQE (2 sont terminées)
339
+
App: récolte les 2 CQE
340
340
```
341
341
342
342
### Mode SQPOLL : zéro appel système
343
343
344
344
Avec le flag `IORING_SETUP_SQPOLL`, le noyau crée un **kernel thread dédié** qui scrute la SQ en permanence. L'application n'a qu'à écrire dans la SQ — pas besoin d'appeler `io_uring_enter` pour soumettre.
345
345
346
346
```
347
-
App: préparer SQE[0] ← simple écriture mémoire
348
-
App: préparer SQE[1] ← simple écriture mémoire
349
-
Kernel thread: détecte les nouvelles SQE, les exécute
350
-
App: récolte les CQE ← simple lecture mémoire
347
+
App: préparer SQE[0] ← simple écriture mémoire
348
+
App: préparer SQE[1] ← simple écriture mémoire
349
+
Kernel thread: détecte les nouvelles SQE, les exécute
350
+
App: récolte les CQE ← simple lecture mémoire
351
351
```
352
352
353
353
Le kernel thread se met en veille après un délai d'inactivité configurable (`sq_thread_idle` dans `params`). Si l'application détecte que le thread dort (via un flag dans la SQ), elle doit appeler `io_uring_enter` pour le réveiller.
@@ -365,17 +365,17 @@ Le flag `IOSQE_IO_LINK` permet de créer des **chaînes de dépendances** entre
365
365
Un cas d'usage classique : « lire depuis un fichier, puis envoyer sur un socket » :
Si la lecture échoue, l'envoi n'est jamais tenté. Sans le chaînage, il faudrait attendre le CQE de la lecture, vérifier le résultat, puis soumettre l'envoi — ce qui double la latence.
373
373
374
374
On peut aussi ajouter un **timeout** à une chaîne :
375
375
376
376
```
377
-
SQE[0]: IORING_OP_RECV flags = IOSQE_IO_LINK
378
-
SQE[1]: IORING_OP_LINK_TIMEOUT (5 secondes)
377
+
SQE[0]: IORING_OP_RECV flags = IOSQE_IO_LINK
378
+
SQE[1]: IORING_OP_LINK_TIMEOUT (5 secondes)
379
379
```
380
380
381
381
Si le `recv` ne se termine pas dans les 5 secondes, il est annulé. Ce pattern remplace les timers manuels courants avec `epoll`.
GIT_TAG liburing-2.7 # Adapter à la version souhaitée
@@ -280,9 +280,9 @@ int get_fd(uint64_t user_data) {
280
280
281
281
// ── Buffers de lecture (un par connexion possible) ──
282
282
// Simplification : tableau statique indicé par fd.
283
-
constexpr int max_conns = 4096;
284
-
constexpr size_t buf_size = 4096;
285
-
char buffers[max_conns][buf_size];
283
+
constexpr int max_conns = 4096;
284
+
constexpr size_t buf_size = 4096;
285
+
char buffers[max_conns][buf_size];
286
286
287
287
// ── Helpers pour préparer les opérations ──
288
288
@@ -546,8 +546,8 @@ Les fonctions liburing suivent deux conventions selon la catégorie :
546
546
547
547
```cpp
548
548
// Convention liburing : le code d'erreur est dans la valeur de retour
549
-
int ret = io_uring_submit(&ring);
550
-
if (ret < 0) {
549
+
int ret = io_uring_submit(&ring);
550
+
if (ret < 0) {
551
551
std::print(stderr, "submit : {}\n", strerror(-ret)); // Notez le -ret
552
552
}
553
553
@@ -560,8 +560,8 @@ if (cqe->res < 0) {
560
560
**`io_uring_get_sqe`** retourne `nullptr` si la SQ est pleine. Ce cas peut survenir si vous préparez plus de SQE que la taille de la SQ sans soumettre entre-temps. La réponse est soit d'augmenter la taille du ring, soit de soumettre plus fréquemment :
561
561
562
562
```cpp
563
-
io_uring_sqe *sqe = io_uring_get_sqe(&ring);
564
-
if (!sqe) {
563
+
io_uring_sqe *sqe = io_uring_get_sqe(&ring);
564
+
if (!sqe) {
565
565
// SQ pleine : soumettre les SQE en attente pour libérer de la place
566
566
io_uring_submit(&ring);
567
567
sqe = io_uring_get_sqe(&ring);
@@ -607,8 +607,8 @@ liburing est une bibliothèque C. En C++ idiomatique, on souhaite une gestion RA
0 commit comments