<style> H2{color:#DF528B !important;} H3{color:#009393 !important;} p{color:Black !important;} li strong {color:#4682b4 !important;} </style> # Event-Based concurrency ## **Intro** ### **How I/O work** * **System call** * `需請求Kernal` * **Kernal maintain a buffer for each I/O device** * <img src="https://i.imgur.com/qCD3f6o.png" width = "300"/></img> ### **Five I/O mode (based on wait)** <img src="https://i.imgur.com/kMaGmPa.png" width = "500"/></img> * **blocking** * `-` * **non-blocking** * `if no data in buffer, return EWOULDBLOCK immediately` * **I/O multiplexing** * `select() and poll()` * `blocked in both wait and copy` * **Signal driven I/O** * `SIGIO` * `nonblocked in wait but blocked in copy` * **ascynchrnous I/O** * `aio()` * `nonblocked all the way.` * `Signal as I/O completed` ## **I/O multiplexing** * I/O multiplexing is to be notified, by kernel, if one or more I/O conditions are ready. * Use select() and poll() ### **Scenario** * **Single thread client** vs.`descriptors`, `sockets` * **Single thread server** vs. * `both TCP and UDP` * `services and protocals` * `TCP server: listening socket & its connected socket` ### **Select** * **Code** * <img src="https://i.imgur.com/GAlPmj3.png" width = "500"/></img> * <img src="https://i.imgur.com/eqDi5Is.png" width = "300"/></img> * **Ready condition 1** : 請求 kernal 測試 input device * `connected socket ready for reading ` * ==socket receive buffer== 達 low-water mark,可以呼叫read() * `listening socket is ready for reading` * 已有新的client連線建立,在complete connection queue,可以呼叫 accept() 取回此新 socket 的 file descriptor * **Ready condition 2** : 請求 kernal 測試 output device * `socket ready for writing` * ==socket send buffer== 的 available space > low-water mark * **summary** * <img src="https://i.imgur.com/X9yBwrc.png" width = "400"/></img> ### **Poll** * **system call** * <img src="https://i.imgur.com/cYGHUPE.png" width = "400"/></img> * **設定** * `bitwise OR AND` * client[0].events = POLLRDNORM | POLLRDBAND; * client[0].revents & POLLRDNORM * <img src="https://i.imgur.com/vJPm4Sm.png" width = "400"/></img> * **3 Classes of Data Identified by poll** * <img src="https://i.imgur.com/iU9NEf7.png" width = "400"/></img> ## **Programming Example** ### **Echo Client** * **問題** :同時使用 fgets, readline 兩個 blocking I/O * `stdin 等 user input,readline 等 socket input` * **解法** : 用 select 同時等 (fgets)stdin, (readline)socket * <img src="https://i.imgur.com/Ar5bvK0.png" width = "400"/></img> * why :`read/write/exceptset 是雙向變數,每次return ,值已被修改,故每次都要reset` * <img src="https://i.imgur.com/VdaWYx9.png" width = "400"/></img> ### **Concurrent TCP server by select** * **keep track of client[] and rset** * `client[]` : client descriptor array * `rset` : readdescriptorset * <img src="https://i.imgur.com/jrtlVo1.png" width = "450"/></img> * **Code** * `Initialization` * <img src="https://i.imgur.com/5vowDuy.png" width = "400"/></img> * `Loop` : 把 connfd 放進 client[] 和 &allset (FD_SET descriptor) * <img src="https://i.imgur.com/XAZfj4o.png" width = "400"/></img> * 從 client[]裡找到 sockfd 並 readline(sockfd) 和 Write() * <img src="https://i.imgur.com/FryQiaI.png" width = "400"/></img> ### **Concurrent TCP server by poll** * **keep track of client[] and pollfd** * `client[]` : client of ==pollfd== structure * struct pollfd = client[OPEN_MAX] * **Code** * `Initialization` * <img src="https://i.imgur.com/t4bEPM9.png" width = "400"/></img> * `Loop` : 把 connfd 放進 client[] 和 &allset (FD_SET descriptor) * <img src="https://i.imgur.com/lU1i4Rb.png" width = "400"/></img> * 從 client[]裡找到 sockfd 並 readline(sockfd) 和 Write() * <img src="https://i.imgur.com/g89cvPj.png" width = "400"/></img> ## **Ascynchrnous I/O** * Issue an I/O request 後 returns immediately * Uses another call to determine whether the request completes ### **使用** * **To issue an asynchronous read to a file** * `issue `==io_read==`(struct aiocb *aiocbp);` * **struct aiocb** * <img src="https://i.imgur.com/GMQHTAY.png" width = "400"/></img> * **To check whether the request has completed** * `call `==io_error==`(const struct aiocb *aiocbp);` * Returns 0 if completed * Returns EINPROGRESS if not yet * Use `signals` (非periodly check) to inform applications when an asynchronous I/O completes * **summary** * <img src="https://i.imgur.com/RMMkM0E.png" width = "400"/></img> ###### tags: `OS`