Coroutine Library in Rust

Overview

coroutine-rs

Build Status crates.io crates.io

Coroutine library in Rust

[dependencies]
coroutine = "0.8"

Usage

Basic usage of Coroutine

extern crate coroutine;

use std::usize;
use coroutine::asymmetric::Coroutine;

fn main() {
    let coro: Coroutine<i32> = Coroutine::spawn(|me,_| {
        for num in 0..10 {
            me.yield_with(num);
        }
        usize::MAX
    });

    for num in coro {
        println!("{}", num.unwrap());
    }
}

This program will print the following to the console

0
1
2
3
4
5
6
7
8
9
18446744073709551615

For more detail, please run cargo doc --open.

Goals

  • Basic single threaded coroutine support

  • Asymmetric Coroutines

  • Symmetric Coroutines

  • Thread-safe: can only resume a coroutine in one thread simultaneously

Notes

  • Basically it supports arm, i686, mips, mipsel and x86_64 platforms, but we have only tested in

    • OS X 10.10.*, x86_64, nightly

    • ArchLinux, x86_64, nightly

Thanks

  • The Rust developers (context switch ASM from libgreen)
Comments
  • Relicense under dual MIT/Apache-2.0

    Relicense under dual MIT/Apache-2.0

    This issue was automatically generated. Feel free to close without ceremony if you do not agree with re-licensing or if it is not possible for other reasons. Respond to @cmr with any questions or concerns, or pop over to #rust-offtopic on IRC to discuss.

    You're receiving this because someone (perhaps the project maintainer) published a crates.io package with the license as "MIT" xor "Apache-2.0" and the repository field pointing here.

    TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that license is good for interoperation. The MIT license as an add-on can be nice for GPLv2 projects to use your code.

    Why?

    The MIT license requires reproducing countless copies of the same copyright header with different names in the copyright field, for every MIT library in use. The Apache license does not have this drawback. However, this is not the primary motivation for me creating these issues. The Apache license also has protections from patent trolls and an explicit contribution licensing clause. However, the Apache license is incompatible with GPLv2. This is why Rust is dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for GPLv2 compat), and doing so would be wise for this project. This also makes this crate suitable for inclusion and unrestricted sharing in the Rust standard distribution and other projects using dual MIT/Apache, such as my personal ulterior motive, the Robigalia project.

    Some ask, "Does this really apply to binary redistributions? Does MIT really require reproducing the whole thing?" I'm not a lawyer, and I can't give legal advice, but some Google Android apps include open source attributions using this interpretation. Others also agree with it. But, again, the copyright notice redistribution is not the primary motivation for the dual-licensing. It's stronger protections to licensees and better interoperation with the wider Rust ecosystem.

    How?

    To do this, get explicit approval from each contributor of copyrightable work (as not all contributions qualify for copyright, due to not being a "creative work", e.g. a typo fix) and then add the following to your README:

    ## License
    
    Licensed under either of
    
     * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
     * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
    
    at your option.
    
    ### Contribution
    
    Unless you explicitly state otherwise, any contribution intentionally submitted
    for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
    additional terms or conditions.
    

    and in your license headers, if you have them, use the following boilerplate (based on that used in Rust):

    // Copyright 2016 coroutine-rs Developers
    //
    // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
    // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
    // http://opensource.org/licenses/MIT>, at your option. This file may not be
    // copied, modified, or distributed except according to those terms.
    

    It's commonly asked whether license headers are required. I'm not comfortable making an official recommendation either way, but the Apache license recommends it in their appendix on how to use the license.

    Be sure to add the relevant LICENSE-{MIT,APACHE} files. You can copy these from the Rust repo for a plain-text version.

    And don't forget to update the license metadata in your Cargo.toml to:

    license = "MIT OR Apache-2.0"
    

    I'll be going through projects which agree to be relicensed and have approval by the necessary contributors and doing this changes, so feel free to leave the heavy lifting to me!

    Contributor checkoff

    To agree to relicensing, comment with :

    I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.
    

    Or, if you're a contributor, you can check the box in this repo next to your name. My scripts will pick this exact phrase up and check your checkbox, but I'll come through and manually review this issue later as well.

    • [x] @cristicbz
    • [x] @doomsplayer
    • [x] @izgzhen
    • [x] @mnussbaum
    • [x] @ra1u
    • [x] @shepmaster
    • [x] @zonyitoo
    opened by emberian 10
  • Using Thread local storage is unsafe

    Using Thread local storage is unsafe

    This is probably not the only api that is affected.

    Right now:

    • A coroutine may migrate from one thread to another
    • A coroutine may yield inside of TLS with block.

    Because of this, it is easy to build a simple test case that violates TLS rules.

    extern crate coroutine;
    
    use coroutine::{spawn, sched};
    use std::cell::RefCell;
    
    thread_local!(static LOCAL: RefCell<u32> = RefCell::new(7));
    
    fn main() {
        let coro = spawn(move|| {
            LOCAL.with(|x| {
                *x.borrow_mut() += 1;
                let ptr: *const RefCell<u32> = x;
                println!("before: {:?} {:?} thread: {:?}", ptr, x, std::thread::current());
                sched();
                let ptr: *const RefCell<u32> = x;
                println!("after: {:?} {:?} thread: {:?}", ptr, x, std::thread::current());
            });
        });
    
        coro.resume().ok().expect("Failed to resume");
    
        std::thread::spawn(move || {
            coro.resume().ok().expect("Failed to resume");
        }).join().unwrap();
    }
    

    This will print:

    before: 0x7f940205a728 RefCell { value: 8 } thread: Some("<main>")
    after: 0x7f940205a728 RefCell { value: 8 } thread: None
    
    bug 
    opened by ghost 9
  • LocalSend instead of Send

    LocalSend instead of Send

    Proposal to fix #31 With this PR I can compile simple example, but can't compile tls example:

    extern crate coroutine;
    
    use coroutine::asymmetric::Coroutine;
    use std::cell::RefCell;
    
    thread_local!(static LOCAL: RefCell<u32> = RefCell::new(7));
    
    fn main() {
        let mut handle = Coroutine::spawn(move|cor| {
            LOCAL.with(|x| {
                *x.borrow_mut() += 1;
                let ptr: *const RefCell<u32> = x;
                println!("before: {:?} {:?} thread: {:?}", ptr, x, std::thread::current());
                cor.yield_with(0);
                let ptr: *const RefCell<u32> = x;
                println!("after: {:?} {:?} thread: {:?}", ptr, x, std::thread::current());
            });
        });
    
        (*handle).yield_with(0);
    
        std::thread::spawn(move || {
            (*handle).yield_with(0);
        }).join().unwrap();
    }
    

    Fails with:

       Compiling coroutine v0.5.0 (file:///home/denis/workspace/github.com/coroutine-rs)
    examples/tls.rs:22:5: 22:23 error: the trait bound `*mut coroutine::asymmetric::Coroutine: std::marker::Send` is not satisfied [E0277]
    examples/tls.rs:22     std::thread::spawn(move || {
                           ^~~~~~~~~~~~~~~~~~
    examples/tls.rs:22:5: 22:23 help: run `rustc --explain E0277` to see a detailed explanation
    examples/tls.rs:22:5: 22:23 note: `*mut coroutine::asymmetric::Coroutine` cannot be sent between threads safely
    examples/tls.rs:22:5: 22:23 note: required because it appears within the type `coroutine::asymmetric::Handle`
    examples/tls.rs:22:5: 22:23 note: required because it appears within the type `[closure@examples/tls.rs:22:24: 24:6 handle:coroutine::asymmetric::Handle]`
    examples/tls.rs:22:5: 22:23 note: required by `std::thread::spawn`
    error: aborting due to previous error
    error: Could not compile `coroutine`.
    
    opened by DenisKolodin 8
  • Explicit access to initial and final values of coroutine

    Explicit access to initial and final values of coroutine

    PR #67 is great, but it has one imperfection: impossible to specify return value when coroutine ends (it return usize::MAX by default. I use library dinamically and take segfaults, because resume expects valid value anytime. We can solve it if closure will return value explicitly, but it makes API quite ugly and forces users to rewrite more code.

    Another ides I tried:

    • Check usize::MAX value, but I have to return additional data.
    • If I will use explicit yield on tail, coroutine will contains invalid is_finished status.

    I've made this PR to solve mentioned problems in better way. This PR takes profits:

    1. Add possibility to get initial value of first resume call (by get_first method of Coroutine)
    2. Add possibility to set final value when coroutine ends to last resume call (by set_last method of Coroutine)
    3. Revert closure type to FnOnce(&mut Coroutine) to prevent user's code changing

    It's more user-friendly, because API not changed and nobody have to change closures, but anyone can control first and last value explicitly.

    @zonyitoo It needs your resoulition.

    opened by DenisKolodin 6
  • Implement `Handle` to a Coroutine

    Implement `Handle` to a Coroutine

    What if two different threads got a Handle to the same Coroutine and then try to resume it concurrently?

    There are multiple choices to apply for this situation:

    1. Make the Handle non-Clonable. This is the most simple solution, but I am still wondering whether it is applicable for most situation.
      • It may not be possible to get a Handle to the current running Coroutine. Because the Environment doesn't own the Coroutine.
    2. Add a conditional variable inside the Handle, when the Coroutine is running, other threads that wants to resume this Coroutine may have to wait for the signal. This solution allows the Handle be Clonable.
    enhancement 
    opened by zonyitoo 6
  • Pushing and pulling parameters.

    Pushing and pulling parameters.

    Do you have any plans/ideas how to implement pushing and pulling parameters between coroutines?

    Something like this:

    • http://www.boost.org/doc/libs/1_58_0/libs/coroutine/doc/html/coroutine/coroutine/asymmetric.html
    • http://www.boost.org/doc/libs/1_58_0/libs/coroutine/doc/html/coroutine/coroutine/symmetric.html
    opened by 3Hren 5
  • Consider renaming the Cargo package to simply

    Consider renaming the Cargo package to simply "coroutine"

    The -rs suffix is redundant, since the fact that it's on crates.io already tells us it's Rust.

    coroutine is still free on crates.io, so now's a great opportunity to grab the name.

    opened by lambda-fairy 5
  • Having one coroutine exit stops the entire program.

    Having one coroutine exit stops the entire program.

    For some reason whenever one of the coroutines created with this crate exit, my entire program also exits. Here is a simple test case that demonstrates the issue:

    extern crate coroutine;
    use coroutine::asymmetric::*;
    
    fn main() {
        let mut c = Coroutine::spawn(move|h, data| {
            h.yield_with(0);
            h.yield_with(0);
            0
        });
        println!("{:?}", c.state());
        c.resume(0);
        println!("{:?}", c.state());
        c.resume(0);
        println!("{:?}", c.state());
        c.resume(0); // exits here
        println!("{:?}", c.state());
        println!("goodbye", );
    }
    
    bug 
    opened by BookOwl 4
  • Specify initial data

    Specify initial data

    Initial data on fisrt resuming is unsound and lost. It's important to take any piece data of resume send.

    This PR fixes it, and makes possible to take value of first resume call.

    It breaks backward compatibility, but not terrible.

    @zonyitoo What's your opinion?

    opened by DenisKolodin 4
  • Can't run example

    Can't run example

    ...
    Build failed, waiting for other jobs to finish...
    failed to run custom build command for `coroutine v0.3.2`
    Process didn't exit successfully: `/home/vi/home/rust/coroutinetest/target/debug/build/coroutine-58be77db9ec74666/build-script-build` (exit code: 101)
    --- stderr
    thread '<main>' panicked at 'Unsupported architecture: i686-unknown-linux-gnu', /home/vi/home/rust/.cargo/registry/src/github.com-48ad6e4054423464/coroutine-0.3.2/build.rs:21
    
    $ rustc --version
    rustc 1.7.0-nightly (2b8e96dad 2015-12-21)
    

    i686 is listed in README although.

    opened by vi 4
  • mismatched types between `c_void` and boxed closure

    mismatched types between `c_void` and boxed closure

    When compiled with nightly rustc, this line will report error:

    src/asymmetric.rs:271:57: 271:74 error: mismatched types:
     expected `*mut libc::types::common::c95::c_void`,
        found `Box<[closure@src/asymmetric.rs:220:23: 269:10 puller_ref:_, f:_, coro_ref:_]>`
    (expected *-ptr,
        found box) [E0308]    
    src/asymmetric.rs:271         coro.context.init_with(coroutine_initialize, 0, Box::new(wrapper), &mut stack);
    

    I searched a bit and find a solution from this post: change Box::new(wrapper) into &wrapper as *const _ as *mut libc::c_void

    It compiled. But honestly, I am not very familiar with low-level rust so I have no idea why the Box::new is wrong and this casting is right.

    opened by izgzhen 4
  • Doesn't seem to build

    Doesn't seem to build

    error[E0432]: unresolved import `std::boxed::FnBox`
      --> /_/code/.cache_rust/registry/src/github.com-1ecc6299db9ec823/coroutine-0.8.0/src/asymmetric.rs:25:5
       |
    25 | use std::boxed::FnBox;
       |     ^^^^^^^^^^^^^^^^^ no `FnBox` in `boxed`
    
    error[E0554]: `#![feature]` may not be used on the stable release channel
      --> /_/code/.cache_rust/registry/src/github.com-1ecc6299db9ec823/coroutine-0.8.0/src/lib.rs:25:12
       |
    25 | #![feature(fnbox)]
       |            ^^^^^
    
    error[E0635]: unknown feature `fnbox`
      --> /_/code/.cache_rust/registry/src/github.com-1ecc6299db9ec823/coroutine-0.8.0/src/lib.rs:25:12
       |
    25 | #![feature(fnbox)]
       |            ^^^^^
    
    

    after adding it to toml.

    opened by installgentoo 1
  • README update with relationship to current Rust?

    README update with relationship to current Rust?

    Thank you for creating coroutine-rs

    I'm just learning, but it seems Rust has some form of either: coroutines, semiroutines or generators, as was implemented to build async/await into Rust.

    Generators Pull Request Claim futures/await is build upon generators/coroutines

    It would be really lovely if the README had some explanatory text discussing the currently use cases for this package. Where it shines, where it might make sense to use Rust core features.

    It's really very hard to figure out the should I use features from this Crate, or build in Rust features as a newcomer to the Rust world.

    opened by cameronelliott 1
  • thread safe documentation

    thread safe documentation

    The text "Thread-safe: can only resume a coroutine in one thread simultaneously" in the readme.md might scare people away. Is this meant to mean "does not implement send and/or sync yet" or "it is inherently unsafe to use in multiple threads"?

    opened by edfraenkel 1
  • Bugfix with std::mem (modern Rust)

    Bugfix with std::mem (modern Rust)

    Can't compile in windows without std::mem import.

    stack_protected.rs

    #[cfg(windows)]
    fn page_size() -> usize {
        unsafe {
            let mut info = mem::zeroed(); // this fails
            libc::GetSystemInfo(&mut info);
            info.dwPageSize as usize
        }
    }
    
    opened by DenisKolodin 1
Owner
Rust中文社区
共同交流有关Rust编程语言的一切话题,QQ2群303838735
Rust中文社区
Rayon: A data parallelism library for Rust

Rayon Rayon is a data-parallelism library for Rust. It is extremely lightweight and makes it easy to convert a sequential computation into a parallel

null 7.8k Jan 7, 2023
Tools for concurrent programming in Rust

Crossbeam This crate provides a set of tools for concurrent programming: Atomics AtomicCell, a thread-safe mutable memory location.(no_std) AtomicCons

Crossbeam 5.7k Dec 30, 2022
Abstract over the atomicity of reference-counting pointers in rust

Archery Archery is a rust library that offers a way to abstraction over Rc and Arc smart pointers. This allows you to create data structures where the

Diogo Sousa 107 Nov 23, 2022
Cross-platform Rust wrappers for the USB ID Repository

usb-ids Cross-platform Rust wrappers for the USB ID Repository. This library bundles the USB ID database, allowing platforms other than Linux to query

William Woodruff 18 Dec 14, 2022
Rust Ethereum 2.0 Client

Lighthouse: Ethereum 2.0 An open-source Ethereum 2.0 client, written in Rust and maintained by Sigma Prime. Documentation Overview Lighthouse is: Read

Sigma Prime 2.1k Jan 6, 2023
Rust Parallel Iterator With Output Sequential Consistency

par_iter_sync: Parallel Iterator With Sequential Output Crate like rayon do not offer synchronization mechanism. This crate provides easy mixture of p

Congyu 1 Oct 30, 2021
Implementação de uma Skip List em Rust

SkipList SkipList é uma estrutura descrita em 1989 por William Pugh que se baseia em balancear de forma probabilística atalhos de um item a outro com

Rodrigo Crispim 3 Apr 27, 2022
Coroutine Library in Rust

coroutine-rs Coroutine library in Rust [dependencies] coroutine = "0.8" Usage Basic usage of Coroutine extern crate coroutine; use std::usize; use co

Rust中文社区 404 Dec 31, 2022
Coroutine I/O for Rust

Coroutine I/O Coroutine scheduling with work-stealing algorithm. WARN: Possibly crash because of TLS inline, check https://github.com/zonyitoo/coio-rs

ty 454 Dec 2, 2022
[no longer maintained] Scalable, coroutine-based, fibers/green-threads for Rust. (aka MIO COroutines).

Documentation mioco Mioco provides green-threads (aka fibers) like eg. Goroutines in Go, for Rust. Status This repo is a complete re-implementation of

Dawid Ciężarkiewicz 137 Dec 19, 2022
Monad/MonadIO, Handler, Coroutine/doNotation, Functional Programming features for Rust

fpRust Monad, Functional Programming features for Rust Why I love functional programming, Rx-style coding. However it's hard to implement them in Rust

null 98 Dec 24, 2022
Coroutine I/O for Rust

Coroutine I/O Coroutine scheduling with work-stealing algorithm. WARN: Possibly crash because of TLS inline, check https://github.com/zonyitoo/coio-rs

ty 454 Dec 2, 2022
cogo rust coroutine database driver (Mysql,Postgres,Sqlite)

cdbc Coroutine Database driver Connectivity.based on cogo High concurrency,based on coroutine No Future<'q,Output=*>,No async fn, No .await , no Poll*

co-rs 10 Nov 13, 2022
🎮 game loop + 🐷 coroutine + 🌯 burrito = 🚀🔥 blazingly synchronous async executor for games 🔥🚀

?? Koryto ?? Pronounced like corrito, which is pronounced as if you combined coroutine and burrito, because everyone knows coroutines are burritos in

Jakub Arnold 3 Jul 6, 2023
Rust 核心库和标准库的源码级中文翻译,可作为 IDE 工具的智能提示 (Rust core library and standard library translation. can be used as IntelliSense for IDE tools)

Rust 标准库中文版 这是翻译 Rust 库 的地方, 相关源代码来自于 https://github.com/rust-lang/rust。 如果您不会说英语,那么拥有使用中文的文档至关重要,即使您会说英语,使用母语也仍然能让您感到愉快。Rust 标准库是高质量的,不管是新手还是老手,都可以从中

wtklbm 493 Jan 4, 2023
Rust library for build scripts to compile C/C++ code into a Rust library

A library to compile C/C++/assembly into a Rust library/application.

Alex Crichton 1.3k Dec 21, 2022
Rust Imaging Library's Python binding: A performant and high-level image processing library for Python written in Rust

ril-py Rust Imaging Library for Python: Python bindings for ril, a performant and high-level image processing library written in Rust. What's this? Th

Cryptex 13 Dec 6, 2022
The gRPC library for Rust built on C Core library and futures

gRPC-rs gRPC-rs is a Rust wrapper of gRPC Core. gRPC is a high performance, open source universal RPC framework that puts mobile and HTTP/2 first. Sta

TiKV Project 1.6k Jan 7, 2023
A µTP (Micro/uTorrent Transport Library) library implemented in Rust

rust-utp A Micro Transport Protocol library implemented in Rust. API documentation Overview The Micro Transport Protocol is a reliable transport proto

Ricardo Martins 134 Dec 11, 2022
A library to compile USDT probes into a Rust library

sonde sonde is a library to compile USDT probes into a Rust library, and to generate a friendly Rust idiomatic API around it. Userland Statically Defi

Ivan Enderlin 40 Jan 7, 2023