C, Rust and more!
All the code used/written in the posts are present in this repository.
1. General posts about C and Rust
1 – Intro to rustenv: If you don’t have sudo access to install the rust toolchain or don’t want to install it globally, you can use rustenv.
2 – Rust Startup: A vanilla introduction to the code that runs before the Rust’s main function.
3 – Primitive Datatypes: An exploratory journey into Rust’s arrays, tuples and integer datatypes.
4 – Calling C code from Rust: It is common to have an existing infra written in C/C++ and wanting to write new code in Rust. In such cases, Rust code will have to call C code. This post gives an intro on how it can be done.
5 – Deciphering Rust’s no_mangle: The #[no_mangle] shows some interesting behavior when I was playing around with Rust FFI. Some of it is documented here.
2. Understanding Event-driven programming and Rust’s async/await
From quite some time, I have wanted to explore Rust’s async/await feature, the tokio runtime, Futures, the async-std - basically the whole asynchronous part of Rust.
A lot of keywords like synchronous, asynchronous, blocking, non-blocking, promises, futures, event, waiting etc., keep floating around and I am having a hard time understanding it. I have some really stupid doubts like if I don’t wait for the I/O I issued, who will wait? Is there someone else waiting for me while I do something else? How will I get notified when that I/O is done? Is a callback registered or is it signal based? Is a new thread spawned which waits for that I/O to happen and joins back once it is done? and many more questions like these. Basically, I have absolutely no clarity over these concepts.
Because of that, I am planning to start with the first time I encountered the word non-blocking I/O - the O_NONBLOCK flag which can be passed to the open() and eventually reach Rust’s async/await concept. In these posts, we will be exploring some interesting system calls like select, poll, epoll, what event-driven means, how it works, does threading play any role etc., I am not sure of the list of things that we might go through because I just know the starting point as of writing this post. Hope is that we will understand what direction we need to go in order to reach Rust’s async/await.
One thing about these posts: These posts are not really refined blog posts. They are way more casual. Might have stupid examples and mistakes as well(I have made sure there are no mistakes though. If there are, please let me know). I am trying to understand these concepts and recording these things will help me understand better.
1 – What does blocking mean?: Gives an introduction to blocking I/O. Introduces the reader to two problems: Can we serve multiple client connections at the same time? Can we somehow bypass the blocking nature of I/O and use that time to do some useful work?
2 – Multithreading and multiprocessing: This post explores the first problem introduced in (1) - Can we serve multiple client connections at the same time?
3 – Is a single thread enough? - Events, Notifications and Event Loop: Explores the idea of a single thread doing literally everything! We rewrite the server using the select system call and discuss some other concepts like events, notification and event-loop.
4 – What is polling?: Explores the idea of polling. Introduces the concept of non-blocking calls along the way. In the end, we implement a single-threaded polling-based server.
5 – Is a single thread enough? - Exploring the epoll system call: TODO
6 –Writing a callback-based event notification library: TODO
In the last couple of posts, we explored a lot of things in C. Started with a single request-response server, then made it into a multithreaded server. Then we explored event notification mechanisms like select and poll - wrote an echo server using them. We saw how multiple connections can be handled with a single thread.
With that, we come to the end of event-driven in C. I hope you have a fair idea of what an event is, what an event-loop looks like, what all happens in it. We started off with understanding the blocking problem and then tried to solve or work around it in a number of ways.
The next couple of posts will revolve around Rust. We will again start by implementing an echo server which uses blocking calls, then slowly build on it in the same way we did in C.
7 – Simple echo server in Rust: An echo server which serves one connection at a time - makes uses of blocking calls.
To be continued.