Skip to content

Consider implementing Singularity's channel contracts #2157

Closed

Description

@brson

In Singularity channels have the useful property that sending never allocates and never blocks. This should allow for a very simple implementation that our semantics don't.

There are some additional enabling properties (or limitations):

  • Each channel has one sender and one receiver
  • Each channel has a defined protocol (channel contract) that must be obeyed

Based on the contract they statically know the maximum number of elements that any queue will hold so they always allocate exactly the right amount. The contract is verified dynamically.

Adopting Singularity-style channels has two potential benefits:

First, contracts on their own are a useful thing, particularly in a language that aims to be 'safe'.

More importantly though it allows the port to use a lock-free circular buffer for the queue. Improving messaging performance is really the only reason we would want to impose more restrictions on channels. Whether this optimization will really pay off in practice I am not sure - there are several other locks on the send and receive paths.

Still not sure this is the right thing to do as it will create more barriers in channel usability, but maybe higher-level abstractions could be built on top.

Activity

  1. boggle commented on Apr 8, 2012

    @boggle
    Contributor

    I see the implementation benefits but in this approach

    1. sending can block badly and in order to avoid this, the user needs to explicitly add its own buffer tasks. This would be in line with rust's idea of being explicit and giving control to the programmer /but/ it is also can be quite difficult to get right without experience with these things. I always liked how erlang's runtime handles these things for the unexperienced developer and manages queue size, processor load and back pressure quite intelligently. So this pushes concerns into user code that may be better left to the runtime.
    2. Concerning distributed channels, this channel contract does not really carry over, as it does not model what happens on the network appropriately, for example:
      • sending the next message before having received an acknowledgement of the last one
      • true multicast/broadcast support of the underlying network
      • I'm even tending to be against FIFO guarantees as that is not a good match for UDP

    Sure these things can be emulated with helper tasks. However channel semantics that directly correspond to network realities simplify re-using of existing code in a distributed setting. If channel and network semantics differ, it can be very hard to put existing software on the network that relies on channel guarantees the network cannot provide without difficulties.

    A middle ground may be providing different channel types that at least document what guarantees are expected.

  2. nikomatsakis commented on Apr 8, 2012

    @nikomatsakis
    Contributor

    This doesn't seem to me that it has to be an "either/or" thing. We can have a simple but flexible form of channels (as in #2158) and a highly optimized, contract-driven form of channels. I don't think it'd be too much of a burden to maintain two channel implementations---or maybe one can be based on the other, as brson suggested---but I'd want to make sure we have a need for both of them. I'd be inclined to start with the simple, flexible form (perhaps as in #2158) and wait until we hit a roadblock for Servo or some other project where messaging performance is a bottleneck. At that point, we might think about refactoring.

  3. boggle commented on Apr 8, 2012

    @boggle
    Contributor

    Yes, I agree. I just think it is quite important to get the set of operations over channels right from the start as much as possible (#1255, broadcasts, timeouts), attach precise and reasonable semantics to the abstraction (perhaps using interfaces) that does not leak the implementation strategy, and provide enough support for using it without being a queueing theory expert ;). These are different issues but I think it is critical to get them right and a good idea to look more at erlang (which has proven that it works) than to look at go (which kind-of still has to).

    From that angle, I'd like rust to somehow (flags, types, interfaces, typestate) differentiate between wether

    • a channel provides FIFO delivery or not,
    • a channel is lossy or not,
    • a channel send may block or not

    and provide a few additional ops (timeouts, broadcasts).

  4. ghost assigned on Jul 6, 2012
  5. eholk commented on Jul 6, 2012

    @eholk
    Contributor

    I've been working on implementing Singularity-style channel contracts. As of 7b03832, there is basic support for it in the compiler. I have a post describing it at http://theincredibleholk.wordpress.com/2012/07/06/rusty-pipes/. The proposal for channel contracts is also available at https://github.com/eholk/rust/wiki/Proposal-for-channel-contracts. So far the performance has been quite good. I'm going to be working on converting more code over to use them to get a feel for whether they are usable.

  6. eholk commented on Jul 25, 2012

    @eholk
    Contributor

    We have these now, so I'm going to close the bug. We could use more syntax extensions, and the pipe compiler needs to be more robust, but basic support is there.

    I intend to try and replace all of the existing Rust communication code with things based on channel contracts, and then hopefully remove the comm module.

  7. added a commit that references this issue on Sep 22, 2022
  8. added a commit that references this issue on Jun 27, 2026
  9. added a commit that references this issue on Aug 21, 2026
    7f1903e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-concurrencyArea: ConcurrencyA-runtimeArea: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflows

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions