55 lines
2.5 KiB
Markdown
55 lines
2.5 KiB
Markdown
# Epore - Learning how to use epoll to Event Queue for non-blocking I/O
|
|
|
|
## Files Structure
|
|
|
|
- `ffi.rs`: This module will contain the code related to the syscalls we need to communicate with the host operating system.
|
|
- `main.rs`: This is the example program itself
|
|
- `poll.rs`: This module contains the main abstraction, which is a thin layer over epoll
|
|
|
|
## Overview
|
|
|
|
- `Poll`: Struct to interface with the OS's event notification system aka event queue (`io_uring`, `epoll`, `kqueue`, `IOCP`).
|
|
|
|
- `new()`: To create a new interface to OS's event queue.
|
|
Similar to [`epoll_create`](https://man7.org/linux/man-pages/man2/epoll_create.2.html)
|
|
- `registry()`: Returns a reference to the registry that we can use to register interest to be notified about new events.
|
|
Similar to [`int epoll_ctl(int epfd, int op, int fd, struct epoll_event *_Nullable event);`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
|
|
- `poll()`: blocks the thread it's called on until an event is ready or its times out, whichever occurs first.
|
|
|
|
- `Registry`: Struct to register interest in a certain `Event`.
|
|
|
|
- `Token`: Using `Token` to track which `TcpStream` socket generated the event.
|
|
|
|
### Sample Usage
|
|
|
|
```rust
|
|
let queue = Poll::new().unwrap();
|
|
let id = 1;
|
|
|
|
// register interest in events on a TcpStream
|
|
queue.registry().register(&stream, id, ...).unwrap();
|
|
|
|
// store the to be tracked events
|
|
let mut events = Vec::with_capacity(1);
|
|
|
|
// This will block the current thread
|
|
queue.poll(&mut events, None).unwrap();
|
|
//...data is ready on one of the tracked streams
|
|
```
|
|
|
|
## How To Run
|
|
|
|
- Get and run the `delayServer` from [Packt's Asynchronous-Programming-in-Rust repo](https://github.com/PacktPublishing/Asynchronous-Programming-in-Rust/tree/main/delayserver).
|
|
|
|
- In another window, run this program with `cargo run`.
|
|
|
|
## Notes
|
|
|
|
### `Registry` and `Poll` Relationship
|
|
|
|
We can see that the struct `Poll` has an internal struct `Registry` inside of it. By moving the struct `Registry` inside of the `Poll` struct, we can call `Registry::try_clone()` to get an owned Registry instance.
|
|
|
|
Therefore, we can pass the `Registry` to other threads with `Arc`, allowing multiple threads to register their interest to the same `Poll` instance even when `Poll` is blocking another thread while waiting for new events to happen in `Poll::poll`
|
|
|
|
`Poll::poll()` requires exclusive access since it takes a `&mut self`, so when we're waiting for events in `Poll::poll()`, there is no way to register interest from a different thread at the same time if we rely on using `Poll` to register.
|