Green Threads in Rust

Green Threads in Rust

Green Threads in Rust KEVIN ROSENDAHL Additional Key Words and Phrases: Rust, Green Threads, Concurrency yield control from the thread, usually back into the runtime which then decides which thread to run next. ACM Reference format: Kevin Rosendahl. 2017. Green Threads in Rust. 1, 1, Article 1 (Decem- ber 2017), 7 pages. 2.2 Green Threads in the Wild https://doi.org/10.1145/nnnnnnn.nnnnnnn Green Threads can be found being used in a number of languages. The usage of green threads most in vogue right now is Go’s "gor- 1 SUMMARY outine." Go implements a green threads runtime that multiplexes goroutines over multiple CPU cores. Go’s runtime however is in For this project, I set out to implement a green threading library charge of scheduling the goroutines; the program does not have to written in Rust that offered an interface as similar as possible to explicitly yield control. std::thread. The most challenging aspect of this was interfacing Rust, in fact, has a history with green threads. A green threads with Rust to accomplish this. Compared to writing a green threading runtime used to be the default paradigm for Rust code. Among other library in C, Rust was very difficult to convince that the implemen- reasons ¹which will be addressed throughout the course of the rest tation is legal. However, once the low level implementation was of the paperº the Rust team decided that having a systems language complete, working in Rust is much better than working in straight use a green threads runtime did not quite align. Thus, they decided C. to abandon the green thread runtime and to switch to using native In the end, I was able to create a working green thread library threads. in Rust that exposes a std::thread like interface. Along the way I ¹ º learned about Rust’s Foreign Function Interface FFI , the underlying 2.3 Event Loops representation of closures and other data types, and gained a much stronger grasp on Rust’s compile-time and runtime checking. Another concurrency pattern that is becoming increasingly popular I was also able to investigate abstractions that can be built on in mainstream programming languages is the event loop. Event top of green threads, and compare them to other concurrency ab- loops have events registered with them, and loop through all of stractions using paradigms other than green threads that attempt the events, handling any that have notified the loop that they are to solve similar problems. ready to be handled. Once all events that had triggered for that loop have been handled, the event loop begins again, handling newly 2 BACKGROUND triggered events. One popular example of an eventloop is libuv, upon which node.js 2.1 Threading is built. Rust also has a popular event loop library mio, upon which Among the different common concurrency paradigms, the most the tokio components are built. popular historically is threading. Threading allows the programmer to essentially write seperate programs that execute concurrently. 2.4 Async I/O, Callbacks, Futures, Promises, and The two main types of threads are "native"/"OS" threads, and Async/Await "green" threads. "Native" or "OS" threads are maintained by the Operating System the program is running on. These threads will Event loops are commonly employed to handle running many dif- usually be multiplexed over multiple CPU cores if they are available, ferent tasks that interact with asynchronous I/O. One method for and are typically preemptively scheduled by the Operating System. handling triggered events is providing a callback function. This Preemptive scheduling means that the program does not have to results in what is commonly referred to as "callback hell," where explicitly say that it yields control over to another thread. Instead, a program devolves into a series of unparsable callback function the Operating System itself will deschedule the thread from the core redirections. it is running on and schedule another thread on it automatically. To combat "callback hell," a number of abstractions have been "Green" threads on the other hand are not scheduled by the Oper- created. Futures provide a value which will eventually be resolved ating System, but instead are scheduled by a runtime running inside into the value it wraps. Promises and the async/await syntax are the program. This is sometimes referred to as "user level" threading attempts at wrapping futures to make the code look more like typical ¹as opposed to "kernel level" threadingº. Commonly, these threads procedural code, rather than evented callback-style code. are scheduled "cooperatively." One problem with these styles of abstractions is that they all still Cooperative scheduling is the opposite of preemptive scheduling. leak. Figure 1 shows the proposed syntax for async/await in Rust. In a cooperative scheduling paradigm, programs must explicitly At a glance, this looks great. The return type is a normal return type, not a future or any other weird type. However, upon further © 2017 Association for Computing Machinery. inspection, we see that the function has to be tagged with #[async]. This is the author’s version of the work. It is posted here for your personal use. Not for And indeed, all functions which end up calling fetch_rust_lang will redistribution. The definitive Version of Record was published in , https://doi.org/10. have to mark themselves with #[async]. Soon, your whole program 1145/nnnnnnn.nnnnnnn. is littered with async notations, and every time you need to change , Vol. 1, No. 1, Article 1. Publication date: December 2017. 1:2 • Rosendahl, K. #[async] #[repr(C)] fn fetch_rust_lang(client: hyper::Client) -> io::Result<String> { pub struct ThreadContext { let response = await!(client.get("https://www.rust-lang.org"))?; pub rsp: u64, if !response.status().is_success() { pub r15: u64, return Err(io::Error::new(io::ErrorKind::Other, "request failed")) pub r14: u64, } pub r13: u64, let body = await!(response.body().concat())?; pub r12: u64, let string = String::from_utf8(body)?; pub rbx: u64, Ok(string) pub rbp: u64, } } Fig. 1. Proposed Rust async/await syntax Fig. 2. ThreadContext grn_context_switch: one function that previously did not call an asynchronous function, # Move current state to old_context mov %rsp, (%rdi) you have to annotate it and every function that ever calls it. mov %r15, 0x08(%rdi) mov %r14, 0x10(%rdi) mov %r13, 0x18(%rdi) 2.5 Relation to CS242 mov %r12, 0x20(%rdi) mov %rbx, 0x28(%rdi) This project has strong ties to the lessons and themes of CS242. As mov %rbp, 0x30(%rdi) I’ve just outlined, the concurrency paradigm that you choose to # Load new state from new_context write your program with has drastic impacts on the syntax, control mov (%rsi), %rsp mov 0x08(%rsi), %r15 flow, and general feel of the code. mov 0x10(%rsi), %r14 In addition to the more subjective ¹but nonetheless incredibly mov 0x18(%rsi), %r13 mov 0x20(%rsi), %r12 importantº aspects described above, the paradigm you choose also mov 0x28(%rsi), %rbx can have an impact on the performance of your application. Later mov 0x30(%rsi), %rbp on we will discuss how the different design choices that can be ret made when writing a concurrency library can impact runtime per- formance. Fig. 3. grn_context_switch 3 APPROACH #[link(name = "context_switch", kind = "static")] extern { 3.1 Why a Rust Green Threads Library? fn grn_context_switch(old_context: *mut libc::c_void, new_context: *const libc::c_void); } Writing a green threads library in Rust was something I was very interested in doing. Last year in CS240, I implemented a very basic Fig. 4. Rust grn_context_switch FFI function green threads library in C ¹with some assemblyº as part of a lab[12]. This got me interested in one day diving deeper into different con- currency techniques. I had been developing node.js applications This Rust wrapper, along with a build script using the cc library for a while and had gotten quite fed up with callback passing, and allows us to call out to the assembly function grn_context_switch. had started to use a fibers library [10]. One interesting thing to note here is the annotation #[repr¹Cº] on Rust has been an interest of mine for a few years now. I’ve found the ThreadContext struct. This tells the Rust compiler that it should its static analysis and compiler guarantees, along with its type sys- lay the struct out in memory as C would, which allows us to use tem, to be incredibly powerful. However, despite writing a few toy the struct as we do in grn_context_switch. projects in Rust I hadn’t yet had any real exposure to solving non- trivial problems in the language. 3.3 Thread Stacks Writing a green threads library in Rust seemed to be a perfect Implementing the context switch required a decent amount of re- marriage of these two interests. search into Rust’s FFI, the compiler, how to get it to link, and the memory layout of structs. That said, it was a pretty straightforward 3.2 Context Switching implementation. No real design decisions had to be made. A key aspect of a green threads library is the ability to context Once you have context switching working, the next step is to switch. That is, to be able to switch the executing control flow create a stack for the eventual green thread to use. This sounds between one green thread to another. straightforward: just allocate some memory and call it a day. How- In order to do this, you need to have the context you want to ever, it turns out there’s a large number of implications depending switch into, and a place to store the current context you’re switching on the strategy you use for stack allocation and management.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    7 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us