---
# System prepended metadata

title: Event-Based concurrency
tags: [OS]

---

<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`
