Compare commits

...
Author SHA1 Message Date
Carl Lerche ecc23c084a chore: prepare v0.2.13 release (#2282)
Includes a quick bug fix
2020-02-28 13:51:24 -08:00
Hiro Saito 937ae11f37 macros: fix unresolved import in pin! (#2281) 2020-02-28 09:36:27 -08:00
Alice Ryhl f0d18653a6 runtime: add threaded_scheduler to examples (#2277)
It can be pretty confusing when the core_threads example does not call
threaded_scheduler, when actually building such a runtime results in
panics if you try to spawn something on it:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=866b3af344b0d6aad170ac9cbc9d57ed
2020-02-27 14:03:18 -08:00
Carl Lerche 06bcbe8dcf sync: refactor intrusive linked list (#2279)
Allow storing the intrusive linked-list pointers in an arbitrary
location in the node. This is in preparation for using the linked list
in the scheduler.

In order to make using the intrusive linked list more flexible, a trait
is introduced to abstract mapping an entry to raw pointers and the next
/ prev pointers. This also pushes more unsafety onto the user.
2020-02-27 13:45:28 -08:00
Carl Lerche bfdfb46fcd chore: delete unused file (#2280)
The `blocking` module is not referenced in code. The file is left over
from an earlier refactor.
2020-02-27 11:57:35 -08:00
Carl Lerche c6fc1db698 chore: prepare v0.2.12 release (#2278)
Also includes `tokio-macros` v0.2.5.
2020-02-27 10:18:01 -08:00
Akshay Narayan d44ce338af tcp: Update listener docs (#2276)
* Update listener docs
* re-wrap text and add links
2020-02-26 21:16:13 +01:00
Carl Lerche 8b7ea0ff5c sync: adds Notify for basic task notification (#2210)
`Notify` provides a synchronization primitive similar to thread park /
unpark, except for tasks.
2020-02-26 11:40:10 -08:00
Thomas Whiteway 7207bf355e time: avoid needing to poll DelayQueue after insertion (#2217)
If an entry is inserted in the queue before the next deadline, the
DelayQueue needs to update the Delay tracking the next time to poll.

If there is an existing Delay, reset that rather than replacing it as if
it's already been polled the task will be waiting for a notification
before it will poll again, and dropping the Delay means that that
notification will never be performed.
2020-02-26 10:55:08 -08:00
David Kellum a4c4ac254b docs: macros doc(cfg) workarounds (#2225)
This is a workaround for the fact that the doc(cfg) from outer cfg_*
macros doesn't get applied correctly. Its included in the rt-threaded
branch only, which is what is used for doc.rs via all-features.
2020-02-26 10:38:54 -08:00
Akshay Narayan 0589acc9ff Implement Stream for Listener types (#2275)
The Incoming types currently don't take ownership of the listener, but
in most cases, users who want to use the Listener as a stream will only
want to use the stream from that point on. So, implement Stream directly
on the Listener types.
2020-02-26 13:38:41 -05:00
Carl Lerche 1dadc701c0 macros: add assignment form to pin! (#2274)
Allows combining assignment to a binding and pinning it.
2020-02-25 20:06:54 -08:00
Kevin Leimkuhler 10f1507cf4 process: Wake up read and write on EPOLLERR (#2218)
## Motivation

#2174

On epoll platforms, the read end of a pipe closing is signaled to the write end
through the `EPOLLERR` event [[1](http://man7.org/linux/man-pages/man2/epoll_ctl.2.html)]. If readiness is not registered for this
event, it will silently pass through `epoll_wait` calls.

Additionally, this specific case that `EPOLLERR` is triggered leaves the write
end of the pipe (parent process) waiting for a wakeup that never occurs.

## Solution

Similar to the `HUP` event on Unix platforms, errors are now always masked
through registrations so that both read and write ends of a connection are made
aware of errors.

In cases where pipes are used and the read end closes, write ends that are
waiting for a wakeup are properly notified and try to write again. This allows
a client to observe `BrokenPipe` and go through the proper cleanup and/or
restablishment of connection.

Closes #2174

Signed-off-by: Kevin Leimkuhler <[email protected]>
2020-02-25 13:27:44 -08:00
Jake b9cc032d3b mpsc: add Sender::send_timeout (#2227) 2020-02-25 09:06:02 -08:00
Thomas 4213b79461 tokio: fix broken contributing guide link (#2267)
The link to the contributing guide in the tokio sub crate was
referencing a non-existent file. This updates the link to reference
the repo root's CONTRIBUTING.md file.

Fixes: #2266
2020-02-22 21:00:58 -08:00
Matt Butcher 7b8ce356c3 sync: fixed a small typo in sync docs (#2262)
Signed-off-by: Matt Butcher <[email protected]>
2020-02-20 11:38:28 -05:00
Alice Ryhl 0605abacfc sync: Use yield rather than block on read method (#2258) 2020-02-20 11:36:08 -05:00
Eliza Weisman b37e4a4380 sync: improve RwLock API docs (#2252)
Currently, the documentation for `tokio::sync::RwLock` states that it
has an unspecified priority policy dependent on the operating system.
This is incorrect: Tokio's `RwLock` is fairly queued. The incorrect
documentation appears to have been copied from the `std::sync::RwLock`
docs, for which this *is* the case.

This commit corrects the documentation to describe the actual priority
policy.

Signed-off-by: Eliza Weisman <[email protected]>
2020-02-18 12:43:29 -08:00
Tudor Sidea 41576e6c48 Added Ord and Hash as derived traits for tokio::time::Instant (#2239)
The added derived traits mirror the traits of std::time::Instant. As
tokio::time::Instant is just a wrapper around std::time::Instant, it
should also derive all the traits std::time::Instant derives.
2020-02-17 11:18:19 -05:00
Waffle Lapkin 09b5f47381 Add Mutex::into_inner method (#2250)
Add `Mutex::into_inner` method that consumes mutex
and return underlying value.

Fixes: #2211
2020-02-17 11:16:48 -05:00
Jon Gjengset fc65951731 UnixStream::poll_shutdown is not a no-op (#2245) 2020-02-14 12:22:29 -05:00
Jon Gjengset 564da5c128 Test some more mpsc behavior with loom (#2246) 2020-02-14 12:03:57 -05:00
Luca Bruno 466dd4a851 rt: lazily detect number of CPUs (#2238)
This tweaks the runtime builder default to defer and lazily
auto-detect the number of CPUs. This is done in order to
avoid performing useless operations which may be expensive
on some platforms (e.g. Linux, where it is coupled to CPU
frequency probing).

Ref: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7d5905dc14a87805a59f3c5bf70173aac2bb18f8
2020-02-13 10:07:06 -08:00
Jon Gjengset 2eed6d00f5 Avoid race in tcp_accept::no_extra_poll (#2236) 2020-02-12 15:53:56 -05:00
Jon Gjengset c1232a6520 io: avoid unnecessary wake in registration (#2221)
See discussion in #2222. This wake/notify call has been there in one
form or another since the very early days of tokio. Currently though, it
is not clear that it is needed; the contract for polling is that you
must keep polling until you get `Pending`, so doing a wakeup when we are
about to return `Ready` is premature.
2020-02-12 11:09:44 -08:00
lord 5e75b0446d Fix doc comment spelling in lib.rs (#2233) 2020-02-11 16:09:40 -05:00
Christian Vallentin d49e6ae1b3 Fixed typos in examples (#2231) 2020-02-11 10:56:32 -05:00
Wade Mealing 874264a4ef Correct link to the guide on tokio.rs (#2229)
The current link to tokio.rs/docs 404's.  This change redirects the "guides" link to the docs overview (which may be what was intended).
2020-02-11 10:56:13 -05:00
Jon GjengsetandCarl Lerche 55b5e1b6ad Fix #2119 and failing state assertion (#2212)
Add a test for #2119 and failing state assertion,
and a fix to go with it.

Co-authored-by: Carl Lerche <[email protected]>
2020-02-04 11:27:18 -05:00
Tore Pettersen 513671f8de stream: add StreamExt::skip_while (#2205)
async version of Iterator::skip_while

Refs: #2104
2020-02-02 11:36:41 -08:00
Alice Ryhl 79e4514283 util: add links to tokio-util + example to BytesCodec (#2207) 2020-02-01 14:04:58 -08:00
Daniel Müller 64e75ad1b0 time: Add comment about cancelation of timed out futures (#2206)
While the module documentation explains that a timed out future (as
created through the tokio::time::timeout function) is canceled, the
function's actual documentation doesn't mention that at all. This change
adds this relevant information to the documentation.
2020-02-01 14:04:17 -08:00
Tore Pettersen 1a5de2c79d stream: add StreamExt::skip (#2204)
skip version of take

Refs: #2104
2020-02-01 14:03:34 -08:00
Carl Lerche ab24a655ad stream: provide StreamMap utility (#2185)
`StreamMap` is similar to `StreamExt::merge` in that it combines source
streams into a single merged stream that yields values in the order that
they arrive from the source streams. However, `StreamMap` has a lot more
flexibility in usage patterns.

`StreamMap` can:

- Merge an arbitrary number of streams.
- Track which source stream the value was received from.
- Handle inserting and removing streams from the set of managed streams
  at any point during iteration.

All source streams held by `StreamMap` are indexed using a key. This key
is included with the value when a source stream yields a value. The key
is also used to remove the stream from the `StreamMap` before the stream
has completed streaming.

Because the `StreamMap` API moves streams during runtime, both streams
and keys must be `Unpin`. In order to insert a `!Unpin` stream into a
`StreamMap`, use `pin!` to pin the stream to the stack or `Box::pin` to
pin the stream in the heap.
2020-01-31 21:18:11 -08:00
Markus Westerlind c3d56b85c3 codec: use advance over split_to when data is not needed (#2198) 2020-01-30 11:26:19 -08:00
roignpar 1eee6508fc sync: fix broadcast link in API docs (#2197) 2020-01-30 11:25:51 -08:00
Sean McArthur 116a18b849 sync: reduce memory size of watch::Receiver (#2191)
This reduces the `mem::size_of::<watch::Receiver>()` from 4 words to 2.

- The `id` is now the pointer of the `Arc<WatchInner>`.
- The `ver` is moved into the `WatchInner`.
2020-01-29 12:22:21 -08:00
Carl Lerche 9d6b99494b rt: add Runtime::shutdown_timeout (#2186)
Provides an API for forcing a runtime to shutdown even if there are
still running tasks.
2020-01-29 12:00:40 -08:00
Tomasz Miąsko 560d0fa548 rt: read join waker conditionally to avoid data race (#2096)
The previous implementation would perform a load that might be part of a
data race. The value read would be used only when race did not occur.
This would be well defined in a memory model where a load that is a part
of race merely returns an undefined value, the Rust memory model on the
other hand defines it to be undefined behaviour.

Perform read conditionally to avoid data race.

Covered by existing loom tests after changing casualty check to be
immediate rather than deferred.

Fixes: #2087
2020-01-29 11:44:15 -08:00
Carl Lerche 6232c74724 macros: correctly feature gate join/try_join (#2196)
The `macros` feature flag was ommitted despite the fact that these
macros require the feature flag to function. The macros are now scoped
by the `macros` feature flag.

This is *not* a breaking change due to the fact that the macros were
broken without the `macros` feature flag in the first place.
2020-01-29 11:16:58 -08:00
Eliza WeismanandWim Looman be832f20cb util: add futures-io/tokio::io compatibility layer (#2117)
* util: add futures-io/tokio::io compatibility layer

This PR adds a compatibility layer with conversions between the
`tokio::io` and `futures-io` versions of the `AsyncRead` and
`AsyncWrite` traits.

I initially opened this PR against `tokio-compat`, but we decided that
a compatibility layer for current versions of the `tokio` and
`futures-io` crates (rather than for compatibility with legacy code)
ought to go in `tokio-util` instead. See:
https://github.com/tokio-rs/tokio-compat/pull/2#issuecomment-551310953

This is based on code originally written by @Nemo157 as part of the
`futures-tokio-compat` crate, and is contributed on behalf of the
original author:
https://github.com/Nemo157/futures-tokio-compat/issues/2#issuecomment-544118866

Closes tokio-rs/tokio-compat#2

Co-authored-by: Wim Looman <[email protected]>
Signed-off-by: Eliza Weisman <[email protected]>
2020-01-29 11:14:24 -08:00
Avery Harnish 326f724978 chore: fix typos in ROADMAP.md (#2190) 2020-01-29 11:12:35 -08:00
Avery Harnish 81c20d8454 chore: improve discoverability of CoC (#2180) 2020-01-29 10:56:11 -08:00
Jon Gjengset b70f1ce3c0 rt: enable task state assertions under loom (#2192) 2020-01-29 10:50:52 -08:00
Vitor Enes 64e4bd1b2f docs: minor fixes to TcpStream API docs (#2183) 2020-01-28 14:07:51 -08:00
Tore 8ed209b612 docs: fix stream::pending() example (#2189) 2020-01-28 11:07:29 -08:00
Lucio Franco 4a24c7063b sync: add mpsc benchmark (#2166) 2020-01-27 20:48:35 -08:00
Juan Alvarez e2230f3392 timer: fix out of bounds error (#2184) 2020-01-27 20:46:52 -08:00
Carl Lerche 00e3c29e48 chore: prepare v0.2.11 release (#2179)
Also bumps:
- tokio-macros: v0.2.4
2020-01-27 10:32:07 -08:00
Carl Lerche bcba4aaa54 docs: write sync mod API docs (#2175)
Fixes #2171
2020-01-27 09:11:12 -08:00
Carl Lerche 71c47fabf4 chore: bump nightly version used in CI (#2178)
This requires fixing a few warnings.
2020-01-26 21:54:14 -08:00
daxpedda 4996e27673 macros: fix skipping generics on #[tokio::main] (#2177)
When using #[tokio::main] on a function with generics, the generics are
skipped. Simply using #vis #sig instead of #vis fn #name(#inputs) #ret
fixes the problem.

Fixes #2176
2020-01-26 09:35:39 -08:00
Carl Lerche 5bf06f2b5a future: provide try_join! macro (#2169)
Provides a `try_join!` macro that supports concurrently driving multiple
`Result` futures on the same task and await the completion of all the
futures as `Ok` or the **first** `Err` future.
2020-01-24 20:26:55 -08:00
Juan Alvarez 12be90e3ff stream: add StreamExt::timeout() (#2149) 2020-01-24 15:22:56 -08:00
Carl Lerche 0d49e112b2 sync: impl equality traits for oneshot::RecvError (#2168) 2020-01-24 15:10:29 -08:00
Avery Harnish 9eca96aa21 rt: improve "no runtime" panic messages (#2145) 2020-01-24 15:10:11 -08:00
Jon Gjengset a16c9a5a01 rt: test block_in_place followed by Pending (#2120) 2020-01-24 15:08:30 -08:00
Dominic f0bfebb7e1 fs: add fs::copy (#2079)
Provides an asynchronous version of `std::fs::copy`.

Closes: #2076
2020-01-24 11:43:26 -08:00
Daniel Fox Franke 968c143acd task: add methods for inspecting JoinErrors (#2051)
Adds `is_cancelled()` and `is_panic()` methods to `JoinError`, as well as
`into_panic()` and `try_into_panic()` methods which, when applicable, returns
the payload of the panic.
2020-01-24 11:23:58 -08:00
wqfish 6fbaac91e0 docs: typo fix in runtime doc (#2167) 2020-01-24 10:56:42 -08:00
David Kellum e35038ed79 rt: add feature flag for using parking_lot internally (#2164)
`parking_lot` provides synchronization primitives that tend to be
more efficient than the ones in `std`. However, depending on
`parking_lot` pulls in a number of dependencies resulting
in additional compilation time.

Adding *optional* support for `parking_lot` allows the end user
to opt-in when the trade offs make sense for their case.
2020-01-24 10:02:19 -08:00
Oleg Nosov f9ddb93604 docs: use third form in API docs (#2027) 2020-01-24 09:31:13 -08:00
Carl Lerche a70f7203a4 macros: add pin! macro (#2163)
Used for stack pinning and based on `pin_mut!` from the pin-util crate.

Pinning is used often when working with stream operators and the select!
macro. Given the small size of `pin!` it makes more sense to include a
version than re-export one from a separate crate or require the user to
depend on `pin-util` themselves.
2020-01-23 14:40:43 -08:00
Carl Lerche 7079bcd609 future: provide join! macro (#2158)
Provides a `join!` macro that supports concurrently driving multiple
futures on the same task and await the completion of all futures.
2020-01-23 13:24:30 -08:00
John-John Tedro f8714e9901 Don't export select unless macros is enabled (#2161) 2020-01-23 18:40:42 +01:00
Artem Vorotnikov 0545b349e1 stream: add StreamExt::fold() (#2122) 2020-01-23 09:03:10 -08:00
Carl Lerche 8cf98d6946 Provide select! macro (#2152)
Provides a `select!` macro for concurrently waiting on multiple async
expressions. The macro has similar goals and syntax as the one provided
by the `futures` crate, but differs significantly in implementation.

First, this implementation does not require special traits to be
implemented on futures or streams (i.e., no `FuseFuture`). A design goal
is to be able to pass a "plain" async fn result into the select! macro.

Even without `FuseFuture`, this `select!` implementation is able to
handle all cases the `futures::select!` macro can handle. It does this
by supporting pre-poll conditions on branches and result pattern
matching. For pre-conditions, each branch is able to include a condition
that disables the branch if it evaluates to false. This allows the user
to guard futures that have already been polled, preventing double
polling. Pattern matching can be used to disable streams that complete.

A second big difference is the macro is implemented almost entirely as a
declarative macro. The biggest advantage to using this strategy is that
the user will not need to alter the rustc recursion limit except in the
most extreme cases.

The resulting future also tends to be smaller in many cases.
2020-01-22 18:59:22 -08:00
kalcutter f9ea576cca sync: fix broadcast bugs (#2135)
Make sure the tail mutex is acquired when `condvar` is notified,
otherwise the wakeup may be lost and the sender could be left waiting.
Use `notify_all()` instead of `notify_one()` to ensure that the correct
sender is woken. Finally, only do any of this when there are no more
readers left.

Additionally, calling `send()` is buggy and may cause a panic when
the slot has another pending send.
2020-01-22 13:59:05 -08:00
Kevin Leimkuhler 7f580071f3 net: add ReadHalf::{poll,poll_peak} (#2151)
The `&mut self` requirements for `TcpStream` methods ensure that there are at
most two tasks using the stream--one for reading and one for writing.

`TcpStream::split` allows two separate tasks to hold a reference to a single
`TcpStream`. `TcpStream::{peek,poll_peek}` only poll for read readiness, and
therefore are safe to use with a `ReadHalf`.

Instead of duplicating `TcpStream::poll_peek`, a private method is now used by
both `poll_peek` methods that uses the fact that only a `&TcpStream` is
required.

Closes #2136
2020-01-22 13:22:10 -08:00
Przemysław Bitkowski 5fe2df0fba docs: fix link to website (#2103)
replace website link, because previous one was broken
2020-01-22 11:06:26 -08:00
Carl Lerche 176df2448a macros: remove unused attributes (#2147) 2020-01-22 10:31:48 -08:00
gliderkite 5bbf976268 Enhance documentation of tokio::task::block_in_place (#2155) 2020-01-22 11:34:09 -05:00
David Barsky 90969420a2 docs: fix incorrectly rendered doc tests; tighten phrasing (#2150) 2020-01-21 21:58:20 -05:00
Carl Lerche bffbaab30d chore: prepare v0.2.10 release (#2148) 2020-01-21 13:33:02 -08:00
Koki Kato a5e774bb38 sync: derive PartialEq for error enums (#2137) 2020-01-21 11:25:44 -08:00
Lucio Franco 0bb17300f7 sync: add std error impl for broadcast errors (#2141) 2020-01-21 11:25:05 -08:00
Lucio Franco c7719a2d29 io: simplify split check (#2144)
* io: Clean up split check

* fix tests
2020-01-21 11:19:36 -08:00
Carl Lerche 38bff0adda macros: fix #[tokio::main] without rt-core (#2139)
The Tokio runtime provides a "shell" runtime when `rt-core` is not
available. This shell runtime is enough to support `#[tokio::main`] and
`#[tokio::test].

A previous change disabled these two attr macros when `rt-core` was not
selected. This patch fixes this by re-enabling the `main` and `test`
attr macros without `rt-core` and adds some integration tests to prevent
future regressions.
2020-01-21 10:46:32 -08:00
Markus Westerlind fbe143b142 fix: Prevent undefined behaviour from malicious AsyncRead impl (#2030)
`AsyncRead` is safe to implement but can be implemented so that it
reports that it read more bytes than it actually did. `poll_read_buf` on
the other head implicitly trusts that the returned length is actually
correct which makes it possible to advance the buffer past what has
actually been initialized.

An alternative fix could be to avoid the panic and instead advance by
`n.min(b.len())`
2020-01-21 10:35:13 -08:00
Carl Lerche 9df805ff54 chore: do not depend on loom on windows (#2146)
Loom currently does not compile on windows due to a
transitive dependency on `generator`. The `generator`
crate builds have started to fail on windows CI. Loom
is not run under windows, however, so removing the
loom dependency on windows is sufficient to fix CI.

Refs: https://github.com/Xudong-Huang/generator-rs/issues/19
2020-01-21 10:15:54 -08:00
Lucio Franco 5d82ac2d1e readme: Add more related tokio projects (#2128) 2020-01-21 10:00:18 -05:00
Maarten de Vries 5bf78d77ad Add a method to test if split streams come from the same stream. (#1762)
* Add a method to test if split streams come from the same stream.

The exposed stream ID can also be used as key in associative containers.

* Document the fact that split stream IDs can dangle.
2020-01-20 19:50:31 -05:00
Vitor Enes 3176d0a48a io: add BufStream::with_capacity (#2125) 2020-01-20 19:27:34 -05:00
David Kellum bb6c3839ef Yield now docs (#2129)
* add subsections for the blocking and yielding examples in task mod

* flesh out yield_now rustdoc

* add a must_use for yield_now
2020-01-20 16:51:47 -05:00
Pierre Krieger 1475448bdf runtime: add Handle::try_current (#2118)
* runtime: add Handle::try_current

Makes it possible to get a Handle only if a Runtime has been started, without panicing if that isn't the case

* Use an error instead
2020-01-20 11:09:52 -05:00
Pen Tree 7eb8d447ad tokio-tls: rename echo.rs to tls-echo.rs (#2133) 2020-01-19 15:53:28 -05:00
Pen Tree 1222d81741 tokio-tls: rename echo.rs to tls-echo.rs (#2133) 2020-01-19 15:27:22 -05:00
Lucio Franco 619d730d61 task: Introduce a new pattern for task-local storage (#2126)
This PR introduces a new pattern for task-local storage. It allows for storage
and retrieval of data in an asynchronous context. It does so using a new pattern
based on past experience.

A quick example:

```rust
tokio::task_local! {
  static FOO: u32;
}

FOO.scope(1, async move {
    some_async_fn().await;
    assert_eq!(FOO.get(), 1);
}).await;
```

## Background of task-local storage

The goal for task-local storage is to be able to provide some ambiant context in
an asynchronous context. One primary use case is for distributed tracing style
systems where a request identifier is made available during the context of a
request / response exchange. In a synchronous context, thread-local storage
would be used for this. However, with asynchronous Rust, logic is run in a
"task", which is decoupled from an underlying thread. A task may run on many
threads and many tasks may be multiplexed on a single thread. This hints at the
need for task-local storage.

### Early attempt

Futures 0.1 included a [task-local storage][01] strategy. This was based around
using the "runtime task" (more on this later) as the scope. When a task was
spawned with `tokio::spawn`, a task-local map would be created and assigned
with that task. Any task-local value that was stored would be stored in this
map. Whenever the runtime polled the task, it would set the task context
enabling access to find the value.

There are two main problems with this strategy which ultimetly lead to the
removal of runtime task-local storage:

1) In asynchronous Rust, a "task" is not a clear-cut thing.
2) The implementation did not leverage the significant optimizations that the
compiler provides for thread-local storage.

### What is a "task"?

With synchronous Rust, a "thread" is a clear concept: the construct you get with
`thread::spawn`. With asynchronous Rust, there is no strict definition of a
"task". A task is most commonly the construct you get when calling
`tokio::spawn`. The construct obtained with `tokio::spawn` will be referred to
as the "runtime task". However, it is also possible to multiplex asynchronous
logic within the context of a runtime task. APIs such as
[`task::LocalSet`][local-set] , [`FuturesUnordered`][futures-unordered],
[`select!`][select], and [`join!`][join] provide the ability to embed a mini
scheduler within a single runtime task.

Revisiting the primary use case, setting a request identifier for the duration
of a request response exchange, here is a scenario in which using the "runtime
task" as the scope for task-local storage would fail:

```rust
task_local!(static REQUEST_ID: Cell<u64> = Cell::new(0));

let request1 = get_request().await;
let request2 = get_request().await;

let (response1, response2) = join!{
    async {
        REQUEST_ID.with(|cell| cell.set(request1.identifier()));
        process(request1)
    },
    async {
        REQUEST_ID.with(|cell| cell.set(request2.identifier()));
        process(request2)
    },
 };
```

`join!` multiplexes the execution of both branches on the same runtime task.
Given this, if `REQUEST_ID` is scoped by the runtime task, the request ID would
leak across the request / response exchange processing.

This is not a theoretical problem, but was hit repeatedly in practice. For
example, Hyper's HTTP/2.0 implementation multiplexes many request / response
exchanges on the same runtime task.

### Compiler thread-local optimizations

A second smaller problem with the original task-local storage strategy is that
it required re-implementing "thread-local storage" like constructs but without
being able to get the compiler to help optimize. A discussion of how the
compiler optimizes thread-local storage is out of scope for this PR description,
but suffice to say a task-local storage implementation should be able to
leverage thread-locals as much as possible.

## A new task-local strategy

Introduced in this PR is a new strategy for dealing with task-local storage.
Instead of using the runtime task as the thread-local scope, the proposed
task-local API allows the user to define any arbitrary scope. This solves the
problem of binding task-locals to the runtime task:

```rust
tokio::task_local!(static FOO: u32);

FOO.scope(1, async move {

    some_async_fn().await;
    assert_eq!(FOO.get(), 1);

}).await;
```

The `scope` function establishes a task-local scope for the `FOO` variable. It
takes a value to initialize `FOO` with and an async block. The `FOO` task-local
is then available for the duration of the provided block. `scope` returns a new
future that must then be awaited on.

`tokio::task_local` will define a new thread-local. The future returned from
`scope` will set this thread-local at the start of `poll` and unset it at the
end of `poll`. `FOO.get` is a simple thread-local access with no special logic.

This strategy solves both problems. Task-locals can be scoped at any level and
can leverage thread-local compiler optimizations.

Going back to the previous example:

```rust
task_local! {
  static REQUEST_ID: u64;
}

let request1 = get_request().await;
let request2 = get_request().await;

let (response1, response2) = join!{
    async {
        let identifier = request1.identifier();

        REQUEST_ID.scope(identifier, async {
            process(request1).await
        }).await
    },
    async {
        let identifier = request2.identifier();

        REQUEST_ID.scope(identifier, async {
            process(request2).await
        }).await
    },
 };
```

There is no longer a problem with request identifiers leaking.

## Disadvantages

The primary disadvantage of this strategy is that the "set and forget" pattern
with thread-locals is not possible.

```rust
thread_local! {
  static FOO: Cell<usize> = Cell::new(0);
}

thread::spawn(|| {
    FOO.with(|cell| cell.set(123));

    do_work();
});
```

In this example, `FOO` is set at the start of the thread and automatically
cleared when the thread terminates. While this is nice in some cases, it only
really logically  makes sense because the scope of a "thread" is clear (the
thread).

A similar pattern can be done with the proposed stratgy but would require an
explicit setting of the scope at the root of `tokio::spawn`. Additionally, one
should only do this if the runtime task is the appropriate scope for the
specific task-local variable.

Another disadvantage is that this new method does not support lazy initialization
but requires an explicit `LocalKey::scope` call to set the task-local value. In
this case since task-local's are different from thread-locals it is fine.

[01]: https://docs.rs/futures/0.1.29/futures/task/struct.LocalKey.html
[local-set]: #
[futures-unordered]: https://docs.rs/futures/0.3.1/futures/stream/struct.FuturesUnordered.html
[select]: https://docs.rs/futures/0.3.1/futures/macro.select.html
[join]: https://docs.rs/futures/0.3.1/futures/macro.join.html
2020-01-17 14:42:52 -05:00
Artem Vorotnikov 476bf0084a chore: minor fixes (#2121)
* One more clippy fix, remove special instructions from CI

* Fix Collect description
2020-01-16 10:29:02 -05:00
Artem Vorotnikov bd8971cd95 chore: clippy fixes (#2110) 2020-01-14 15:12:08 -08:00
Carl Lerche eb1a8e1792 stream: add StreamExt::collect() (#2109)
Provides an asynchronous equivalent to `Iterator::collect()`. A sealed
`FromStream` trait is added. Stabilization is pending Rust supporting
`async` trait fns.
2020-01-13 14:44:06 -08:00
John-John Tedro 5b091fa3f0 io: Drop AsyncBufRead bound on BufStream impl (#2108)
fixes #2064, #2106
2020-01-13 11:33:24 -08:00
Carl Lerche 7c3f1cb4a3 stream: add StreamExt::chain (#2093)
Asynchronous equivalent to `Iterator::chain`.
2020-01-11 16:33:52 -08:00
Carl Lerche 64d2389911 stream: add stream::once (#2094)
An async equivalent to `iter::once`
2020-01-11 13:52:51 -08:00
Carl Lerche 8471e0a0ee stream: add empty() and pending() (#2092)
`stream::empty()` is the asynchronous equivalent to
`std::iter::empty()`. `pending()` provides a stream that never becomes
ready.
2020-01-11 12:32:19 -08:00
Carl Lerche 0ba6e9abdb stream: add StreamExt::merge (#2091)
Provides an equivalent to stream `select()` from futures-rs. `merge`
best describes the operation (vs. `select`). `futures-rs` named the
operation "select" for historical reasons and did not rename it back to
`merge` in 0.3. The operation is most commonly named `merge` else where
as well (e.g. ReactiveX).
2020-01-11 12:31:59 -08:00
Jake Rawsthorne a939dc48b0 sync: impl From<T> and Default for RwLock (#2089) 2020-01-10 14:22:37 -08:00
Carl Lerche cfd9b36d89 stream: add StreamExt::fuse (#2085) 2020-01-09 20:51:06 -08:00
Lucio Franco f5c20cd228 chore: update Tokio discord url (#2086) 2020-01-09 20:41:07 -08:00
Carl Lerche c7c74a5a76 chore: prepare v0.2.9 release (#2084) 2020-01-09 14:20:46 -08:00
Aljoscha Krettek b34a849b79 docs: fix runtime creation doc in tokio::runtime (#2073)
With the rt-threaded feature flag we create a threaded scheduler by
default. The documentation had a copy-and-paste error from the section
about the basic scheduler.
2020-01-09 12:44:42 -08:00
Tomasz Miąsko a7a79f28a8 rt: use release ordering in drop_join_handle_fast (#2044)
Previously acquire operations reading a value written by a successful
CAS in `drop_join_handle_fast` did not synchronize with it. The CAS
wasn't guaranteed to happen before the task deallocation, and so
created a data race between the two.

Use release success ordering to ensure synchronization.
2020-01-09 12:06:11 -08:00
Yoshiya Hinosawa bd28a7a767 docs: fix typo and issue reference (#2080) 2020-01-09 11:50:48 -08:00
Carl Lerche 275769b5b9 rt: fix shutdown deadlock in threaded scheduler (#2082)
Previously, when the threaded scheduler was in the shutdown process, it
would hold a lock while dropping in-flight tasks. If those tasks
included a drop handler that attempted to wake a second task, the wake
operation would attempt to acquire a lock held by the scheduler. This
results in a deadlock.

Dropping the lock before dropping tasks resolves the problem.

Fixes #2046
2020-01-09 11:49:18 -08:00
Lucio Franco b70615b299 docs: document feature flags (#2081) 2020-01-09 10:38:53 -08:00
Carl Lerche 6406328176 rt: fix threaded scheduler shutdown deadlock (#2074)
Previously, if an IO event was received during the runtime shutdown
process, it was possible to enter a deadlock. This was due to the
scheduler shutdown logic not expecting tasks to get scheduled once the
worker was in the shutdown process.

This patch fixes the deadlock by checking the queues for new tasks after
each call to park. If a new task is received, it is forcefully shutdown.

Fixes #2061
2020-01-08 21:23:10 -08:00
Jeb Rosen f28c9f0d17 Fix Seek adapter and AsyncSeek error handling for File
* io: Fix the Seek adapter and add a tested example.

  If the first 'AsyncRead::start_seek' call returns Ready,
  'AsyncRead::poll_complete' will be called.

  Previously, a start_seek that immediately returned 'Ready' would cause
  the Seek adapter to return 'Pending' without registering a Waker.

* fs: Do not return write errors from methods on AsyncSeek.

  Write errors should only be returned on subsequent writes or on flush.

  Also copy the last_write_err assert from 'poll_read' to both
  'start_seek' and 'poll_complete' for consistency.
2020-01-08 19:15:57 -08:00
Alice Ryhl 7ee5542182 doc: fix old notes regarding examples and async/await (#2071) 2020-01-07 15:55:10 -08:00
Carl Lerche 7fb54315f1 macros: fix breaking changes (#2069)
Brings back old macro implementations and updates the version of
tokio-macros that tokio depends on.

Prepares a new release.
2020-01-07 14:29:44 -08:00
Artem Vorotnikov ffd4025fce chore: prepare tokio-macros v0.2.2 release (#2068) 2020-01-07 16:44:27 -05:00
Carl Lerche 8bf4696f31 chore: prepare v0.2.7 release (#2065) 2020-01-07 11:40:49 -08:00
Carl Lerche 10398b20c0 docs: minor tweaks to StreamExt API docs (#2066) 2020-01-07 11:40:37 -08:00
Alice Ryhl 780d6f91a0 docs: improve tokio::io API documentation (#2060)
* Links are added where missing and examples are improved.
* Improve `stdin`, `stdout`, and `stderr` documentation by going
  into more details regarding what can go wrong in concurrent
  situations and provide examples for `stdout` and `stderr`.
2020-01-07 09:17:01 -08:00
Carl Lerche 45da5f3510 rt: cleanup runtime::context (#2063)
Tweak context to remove more fns and usage of `Option`. Remove
`ThreadContext` struct as it is reduced to just `Handle`. Avoid passing
around individual driver handles and instead limit to the
`runtime::Handle` struct.
2020-01-07 07:53:40 -08:00
Sean McArthur 855d39f849 Fix basic_scheduler deadlock when waking during drop (#2062) 2020-01-06 15:37:03 -08:00
Eliza Weisman 798e86821f task: add ways to run a LocalSet from within a rt context (#1971)
Currently, the only way to run a `tokio::task::LocalSet` is to call its
`block_on` method with a `&mut Runtime`, like

```rust
let mut rt = tokio::runtime::Runtime::new();
let local = tokio::task::LocalSet::new();
local.block_on(&mut rt, async {
  // whatever...
});
```

Unfortunately, this means that `LocalSet` doesn't work with the 
`#[tokio::main]`  and `#[tokio::test]` macros, since the `main` 
function is _already_ inside of a call to `block_on`.

**Solution**

This branch adds a `LocalSet::run` method, which takes a future and
returns a new future that runs that future on the `LocalSet`. This
is analogous to `LocalSet::block_on`, except that it can be called in
an async context.

Additionally, this branch implements `Future` for `LocalSet`. Awaiting
a `LocalSet` will run all spawned local futures until they complete.
This allows code like

```rust
#[tokio::main] 
async fn main() {
    let local = tokio::task::LocalSet::new();

    local.spawn_local(async {
        // ...
    });

    local.spawn_local(async {
        // ...
        tokio::task::spawn_local(...);
        // ...
    });

    local.await;
}
```

The `LocalSet` docs have been updated to show the usage with 
`#[tokio::main]` rather than with manually created runtimes, where
applicable.

Closes #1906 
Closes #1908 
Fixes #2057
2020-01-06 14:44:30 -08:00
Benjamin Fry 0193df3a59 rt: add a Handle::current() (#2040)
Adds `Handle::current()` for accessing a handle to the runtime
associated with the current thread. This handle can then be
passed to other threads in order to spawn or perform other
runtime related tasks.
2020-01-06 11:32:21 -08:00
Tomasz Miąsko 5930acef73 rt: share vtable between waker and waker ref (#2045)
The `Waker::will_wake` compares both a data pointer and a vtable to
decide if wakers are equivalent. To avoid false negatives during
comparison, use the same vtable for a waker stored in `WakerRef`.
2020-01-06 10:39:48 -08:00
Artem Vorotnikov 3540c5b9ee stream: Add StreamExt::any (#2034) 2020-01-06 10:26:53 -08:00
Ivan Petkov 188fc6e0d2 process: deprecate Child stdio accessors in favor of pub fields (#2014)
Fixes #2009
2020-01-06 10:24:40 -08:00
Stepan Koltsov d45f61c183 doc: document from_std functions panic (#2056)
Document that conversion from `std` types must be done from within
the Tokio runtime context.
2020-01-06 10:06:39 -08:00
Linus Färnstrand dcfa895b51 chore: use just std instead of ::std in paths (#2049) 2020-01-06 10:04:21 -08:00
Carl Lerche f0006006ed time: advance frozen time in park_timeout (#2059)
This patch improves the behavior of frozen time (a testing utility made
available with the `test-util` feature flag). Instead of of requiring
`time::advance` to be called in order to advance the value returned by
`Instant::now`, calls to `time::Driver::park_timeout` will use the
provided duration to advance the time.

This is the desired behavior as the timeout is used to indicate when the
next scheduled delay needs to be fired.
2020-01-06 08:47:34 -08:00
John Van Enk 84ff73e687 tokio: remove documentation stating Receiver is clone-able. (#2037)
* tokio: remove documentation stating `Receiver` is clone-able.

The documentation for `broadcast` stated that both `Sender` and
`Receiver` are clonable. This isn't the case: `Receiver`s cannot be
cloned (and shouldn't be cloned).

In addition, mention that `Receiver` is `Sync`, and mention that both
`Receiver` and `Sender` are `Send`.

Fixes: #2032

* Clarify that Sender and Receiver are only Send and Sync if T is Send or Sync.
2020-01-06 11:28:26 -05:00
João Oliveira 32e15b3a24 sync: add RwLock (#1699)
Provides a `RwLock` based on a semaphore. The semaphore is initialized
with 32 permits. A read acquires a single permit and a write acquires all 32
permits. This ensures that reads (up to 32) may happen concurrently and
writes happen exclusively.
2020-01-03 21:03:26 -08:00
Carl Lerche efcbf9613f sync: add batch op support to internal semaphore (#2004)
Extend internal semaphore to support batch operations. With this PR,
consumers of the semaphore are able to atomically request more than one
permit. This is useful for implementing a RwLock.
2020-01-03 10:34:15 -08:00
Artem Vorotnikov 3736467dbb stream: correct trait bounds for all (#2043) 2020-01-02 15:03:53 -08:00
Artem Vorotnikov e43f28f6a8 macros: do not automatically pull rt-core (#2038) 2020-01-02 11:22:15 -08:00
Artem Vorotnikov 3cf91db4b6 stream: add StreamExt::all (#2035) 2020-01-02 11:36:38 -05:00
Artem Vorotnikov e8fcf55881 Refactor proc macros, add more knobs (#2022)
* Refactor proc macros, add more knobs

* make macros work with rt-core
2019-12-27 13:56:43 -05:00
Artem Vorotnikov a515f9c459 stream: add StreamExt::take_while (#2029) 2019-12-25 12:48:02 -08:00
Carl Lerche 50b91c0247 chore: move benches to separate crate (#2028)
This allows the `benches` crate to depend on `tokio` with all feature
flags. This is a similar strategy used for `examples`.
2019-12-24 20:53:20 -08:00
Gardner Vickers 67bf9c36f3 rt: coalesce thread-locals used by the runtime (#1925)
Previously, thread-locals used by the various drivers were situated
with the driver code. This resulted in state being spread out and many
thread-locals being required to run a runtime.

This PR coalesces the thread-locals into a single struct.
2019-12-24 15:34:47 -08:00
Artem Vorotnikov 101f770af3 stream: add StreamExt::take (#2025) 2019-12-24 08:20:02 -08:00
Stephen Carman 6ff4e349e2 doc: add additional Mutex example (#2019) 2019-12-23 10:18:30 -08:00
Carl Lerche adc5186ebd rt: fix storing Runtime in thread-local (#2011)
Storing a `Runtime` value in a thread-local resulted in a panic due to
the inability to access the parker.

This fixes the bug by skipping parking if it fails. In general, there
isn't much that we can do besides not parking.

Fixes #593
2019-12-22 13:03:44 -08:00
Carl Lerche 7b53b7b659 doc: fill out fs and remove html links (#2015)
also add an async version of `fs::canonicalize`
2019-12-22 12:55:09 -08:00
baizhenxuan 99fa93bf0e tokio-tls: fix examples build and run (#1963) 2019-12-22 11:48:08 -08:00
Ruben De Smet 0133bc1883 time: DelayQueue::len() (#1755) 2019-12-21 18:18:49 -08:00
Bhargav a854094825 sync: impl Stream for broadcast::Receiver (#2012) 2019-12-21 14:38:05 -08:00
Carl Lerche 3d1b4b3058 rt: fix spawn_blocking from spawn_blocking (#2006)
Nested spawn_blocking calls would result in a panic due to the necessary
context not being setup. This patch sets the blocking pool context from
within a blocking pool.

Fixes #1982
2019-12-21 13:19:52 -08:00
Artem Vorotnikov 8656b7b8eb chore: fix formatting, remove old rustfmt.toml (#2007)
`cargo fmt` has a bug where it does not format modules scoped with
feature flags.
2019-12-21 12:28:57 -08:00
fbucek f309b295bb doc: fix misleading comment in interval.rs 2019-12-21 09:31:02 -08:00
Artem Vorotnikov b1266a48c4 Fix UdpFramed doc cfg_attr (#2010) 2019-12-21 12:04:30 -05:00
David Barsky de5ec6e1bc dns: provide lookup_host function (#1870)
`ToSocketAddrs` is a sealed trait pending changes in Rust that will allow
defining async trait fns. Until then, `net::lookup_host` is provided as a way
to convert a `T: ToSocketAddrs` into `SocketAddr`s.
2019-12-21 08:30:00 -08:00
Artem Vorotnikov 3dcd76a38f stream: StreamExt::try_next (#2005) 2019-12-20 21:27:14 -08:00
Artem Vorotnikov 3b9c7b1715 stream: filtering utilities (#2001)
Adds `StreamExt::filter` and `StreamExt::filter_map`.
2019-12-20 20:17:05 -08:00
Artem Vorotnikov 3bff5a3ffe chore: formatting, docs and clippy (#2000) 2019-12-20 13:54:43 -08:00
Carl Lerche 248bf2144f prepare v0.2.6 release (#1995) 2019-12-19 14:02:07 -08:00
Carl Lerche 93ab70a9a0 fs: add deprecated fs::File::seek fn (#1991)
This fixes an API compatibility regression when `AsyncSeek` was added.

Fixes: #1989
2019-12-19 13:37:10 -08:00
João Oliveira 58b5abdb99 update connect example (#1787) 2019-12-18 19:54:06 -05:00
Carl Lerche 2d78cfe56a chore: prepare v0.2.5 release (#1984)
Also includes:
- `tokio-macros` v0.2.1
2019-12-18 13:07:27 -08:00
Artem Vorotnikov 4c645866ef stream: add next and map utility fn (#1962)
Introduces `StreamExt` trait. This trait will be used to add utility functions
to make working with streams easier. This patch includes two functions:

* `next`: a future returning the item in the stream.
* `map`: transform each item in the stream.
2019-12-18 11:57:22 -08:00
Carl Lerche b0836ece7a sync: encapsulate TryLockError variants (#1980)
As there is currently only one variant, make the error type an opaque
struct.
2019-12-18 11:50:56 -08:00
Douman 0c0f682010 Improve runtime threading options docs 2019-12-18 20:14:22 +01:00
Douman b24ad9fe86 rt: add configuration for core threads and max threads (#1977)
`num_threads` is deprecated. Instead, `core_threads` and `max_threads` are
introduced. `core_threads` specifies the number of "always on" threads used
for the async task executor and `max_threads` specifies the maximum number
of threads that the runtime may spawn.
2019-12-18 10:31:49 -08:00
Carl Lerche 7c010ed030 sync: add broadcast channel (#1943)
Adds a broadcast channel implementation. A broadcast channel is a
multi-producer, multi-consumer channel where each consumer receives a
clone of every value sent. This is useful for implementing pub / sub
style patterns.

Implemented as a ring buffer, a Vec of the specified capacity is
allocated on initialization of the channel. Values are pushed into
slots.

When the channel is full, a send overwrites the oldest value. Receivers
detect this and return an error on the next call to receive. This
prevents unbounded buffering and does not make the channel vulnerable to
the slowest consumer.

Closes: #1585
2019-12-18 10:13:15 -08:00
Dmitrii Goriunov 42c942de14 Fix ROADMAP link (#1981) 2019-12-18 09:54:35 -05:00
Kelly Thomas Kline 5e8f7eb03c docs: correct spelling (#1974) 2019-12-17 22:52:40 -08:00
Michael P. Jung 9211adbe01 sync: add Semaphore (#1973)
Provide an asynchronous Semaphore implementation. This is useful for
synchronizing concurrent access to a shared resource.
2019-12-17 22:32:12 -08:00
yim7 e5b99b0f7a sync: print MutexGuard inner value for debugging (#1961) 2019-12-17 22:02:31 -08:00
Carl Lerche 83cd754bc8 rt: fix blocking pool shutdown logic (#1978)
The blocking task queue was not explicitly drained as part of the
blocking pool shutdown logic. It was originally assumed that the
contents of the queue would be dropped when the blocking pool structure
is dropped. However, tasks must be explicitly shutdown, so we must drain
the queue can call `shutdown` on each task.

Fixes #1970, #1946
2019-12-17 21:24:26 -08:00
Ruben De Smet 17e424112d time: impl Stream for DelayQueue (#1975) 2019-12-17 21:01:29 -08:00
Carl Lerche 41d15ea212 rt: avoid dropping a task in calls to wake() (#1972)
Calls to tasks should not be nested. Currently, while a task is being
executed and the runtime is shutting down, a call to wake() can result
in the wake target to be dropped. This, in turn, results in the drop
handler being called.

If the user holds a ref cell borrow, a mutex guard, or any such value,
dropping the task inline can result in a deadlock.

The fix is to permit tasks to be scheduled during the shutdown process
and dropping the tasks once they are popped from the queue.

Fixes #1929, #1886
2019-12-17 20:52:09 -08:00
Kelly Thomas Kline 8add90210b docs: correct grammar (#1968) 2019-12-17 13:57:25 -08:00
Kelly Thomas Kline efb4b67a54 chore: add roadmap (#1965) 2019-12-16 09:39:49 -08:00
Vlad-Shcherbina 74d33a1b2f Fix typo in sync documentation (#1942) 2019-12-14 10:17:36 -08:00
Jake Goulding 69885e214c Enable the full feature when compiled for the playground (#1960)
Closes #1932
2019-12-14 10:16:20 -08:00
Artem Vorotnikov 4b85565bd7 time: stream throttle (#1949) 2019-12-13 22:06:41 -08:00
Artem Vorotnikov d593c5b051 chore: remove benches and fix/work around clippy lints (#1952) 2019-12-13 22:01:47 -08:00
Douman 91ecb4b4c2 macros: inherit visibility 2019-12-13 19:33:44 +01:00
Sean McArthur 8abaf89e5f Re-enable writev support in TcpStreams (#1956) 2019-12-13 10:25:27 -08:00
Carl Lerche b560df9e66 chore: fix warning in tokio-util tests (#1955)
`bytes` added a warning when using a fn that resulted in a useless
clone.
2019-12-13 10:03:10 -08:00
Mathspy df8278acb6 Fix typo with updated docs (#1920)
I think this is a typo
2019-12-12 14:55:25 -05:00
nickelc 5862b9a2e0 chore: fix the outdated example in README (#1930) 2019-12-11 14:12:53 -08:00
Carl Lerche c0953d41a5 chore: fix thread_pool benchmarks (#1947)
Update the rotted thread_pool benchmarks. These benchmarks are not the
greatest, but as of now it is all we have for micro benchmarks.

Adds a little yielding in the parker as it helps a bit.
2019-12-11 12:44:45 -08:00
Michael HowellandTaiki Endo 24cd6d67f7 io: add AsyncSeek trait (#1924)
Co-authored-by: Taiki Endo <[email protected]>
2019-12-10 21:48:24 -08:00
Michael P. Jung 975576952f Add Mutex::try_lock and (Unbounded)Receiver::try_recv (#1939) 2019-12-10 08:01:23 -08:00
Juan Alvarez 5d5755dca4 fix spawn function documentation (#1940) 2019-12-10 10:46:48 -05:00
Danilo Bargen 41ffdbb7d9 sync::Mutex: Fix typo in documentation (#1934) 2019-12-09 15:07:21 -05:00
Danilo Bargen 2450b5bfc9 sync::Mutex: Add note about the absence of poisoning (#1933) 2019-12-09 09:13:24 -08:00
Carl Lerche 80abff0e57 chore: prepare v0.2.4 release (#1917)
Includes a `Mutex` bug fix
2019-12-06 19:50:29 -08:00
Michael P. Jung c632337e6f sync: fix Mutex when lock future dropped before complete (#1902)
The bug caused the mutex to reach a state where it is locked and cannot be unlocked.

Fixes #1898
2019-12-06 14:30:02 -08:00
Carl Lerche a53f94ab61 doc: expand on runtime / spawn docs (#1914) 2019-12-06 13:10:18 -08:00
Carl Lerche 98c9a77f18 prepare v0.2.3 release (#1912) 2019-12-06 09:47:28 -08:00
Carl Lerche e00c49611a doc: fix TcpListener example to compile (#1911)
The `process_socket` is hidden from the user which makes the example
fail to compile if copied by the reader.
2019-12-06 09:16:08 -08:00
Jeremy Kolb 9c9fabc44b Close markdown (#1910) 2019-12-06 07:51:24 -08:00
Steven Fackler c3461b3ef3 time: impl From between std / tokio Instants (#1904) 2019-12-05 12:03:04 -08:00
Eliza Weisman b7ecd35036 task: fix LocalSet failing to poll all local futures (#1905)
Currently, a `LocalSet` does not notify the `LocalFuture` again at the
end of a tick. This means that if we didn't poll every task in the run
queue during that tick (e.g. there are more than 61 tasks enqueued),
those tasks will not be polled.

This commit fixes this issue by changing `local::Scheduler::tick` to
return whether or not the local future needs to be notified again, and
waking the task if so.

Fixes #1899
Fixes #1900

Signed-off-by: Eliza Weisman <[email protected]>
2019-12-05 12:00:10 -08:00
Kevin Leimkuhler dbcd1f9a09 time: Remove HandlePriv (#1896)
## Motivation

#1800 removed the lazy binding of `Delay`s to timers. With the removal of the
logic required for that, `HandlePriv` is no longer needed. This PR removes the
use of `HandlePriv`.

A `TODO` was also removed that would panic if when registering a new `Delay`
the current timer handle was full. That has been fixed to now immediately
transition that `Delay` to an error state that can be handled in a similar way
to other error states.

Signed-off-by: Kevin Leimkuhler <[email protected]>
2019-12-04 20:46:16 -08:00
Eliza Weisman 0e729aa341 task: fix infinite loop when dropping a LocalSet (#1892)
## Motivation

There's currently an issue in `task::LocalSet` where dropping the local
set can result in an infinite loop if a task running in the local set is
notified from outside the local set (e.g. by a timer). This was reported
in issue #1885.

This issue exists because the `Drop` impl for `task::local::Scheduler`
does not drain the queue of tasks notified externally, the way the basic
scheduler does. Instead, only the local queue is drained, leaving some
tasks in place. Since these tasks are never removed, the loop that
continues trying to cancel tasks until the owned task list is totally
empty continues infinitely.

I think this issue was due to the `Drop` impl being written before a
remote queue was added to the local scheduler, and the need to close the
remote queue as well was overlooked.

## Solution

This branch solves the problem by clearing the local scheduler's remote
queue as well as the local one.

I've added a test that reproduces the behavior. The test fails on master
and passes after this change.

In addition, this branch factors out the common task queue logic in the
basic scheduler runtime and the `LocalSet` struct in `tokio::task`. This
is because as more work was done on the `LocalSet`, it has gotten closer
and closer to the basic scheduler in behavior, and factoring out the
shared code reduces the risk of errors caused by `LocalSet` not doing
something that the basic scheduler does. The queues are now encapsulated
by a `MpscQueues` struct in `tokio::task::queue` (crate-public).  As a
follow-up, I'd also like to look into changing this type to use the same
remote queue type as the threadpool (a linked list).

In particular, I noticed the basic scheduler has a flag that indicates
the remote queue has been closed, which is set when dropping the
scheduler. This prevents tasks from being added after the scheduler has
started shutting down, stopping a potential task leak. Rather than
duplicating this code in `LocalSet`, I thought it was probably better to
factor it out into a shared type.

There are a few cases where there are small differences in behavior,
though, so there is still a need for separate types implemented _using_
the new `MpscQueues` struct. However, it should cover most of the 
identical code.

Note that this diff is rather large, due to the refactoring. However, the
actual fix for the infinite loop is very simple. It can be reviewed on its own
by looking at commit 4f46ac6. The refactor is in a separate commit, with
the SHA 90b5b1f.

Fixes #1885

Signed-off-by: Eliza Weisman <[email protected]>
2019-12-04 11:20:57 -08:00
Artem Vorotnikov cbe369a3ed Make JoinError Sync (#1888)
* Make JoinError Sync

* Move Mutex inside JoinError internals, hide its constructors

* Deprecate JoinError constructors, fix internal usages
2019-12-04 10:51:23 -08:00
Juan Alvarez 8bcbe78dbe remove io workarounds from example (#1891)
This PR removes no longer needed io workarounds from connect example.
2019-12-03 16:07:09 -08:00
Christopher Coverdale 6efe07c3fb Fixing minor spelling mistake in task docs (#1889) 2019-12-03 12:01:59 -08:00
Xinkai Chen 8a2160a913 Add unit tests for tokio::File::AsRaw{Fd,Handle} for Unix and Windows. (#1890)
Supersedes #1640.
2019-12-03 09:56:32 -08:00
baizhenxuan 38c361781f examples: fix tinyhttp (#1884) 2019-12-02 20:28:36 -08:00
Eliza Weisman 07451f8b94 task: relax 'static bound in LocalSet::block_on (#1882)
## Motivation

Currently, `tokio::task::LocalSet`'s `block_on` method requires the
future to live for the 'static lifetime. However, this bound is not
required — the future is wrapped in a `LocalFuture`, and then passed
into `Runtime::block_on`, which does _not_ require a `'static` future.

This came up while updating `tokio-compat` to work with version 0.2. To
mimic the behavior of `tokio` 0.1's `current_thread::Runtime::run`, we
want to be able to have a runtime block on the `recv` future from an
mpsc channel indicating when the runtime is idle. To support `!Send`
futures, as the old `current_thread::Runtime` did, we must do so inside
of a `LocalSet`. However, with the current bounds, we cannot await an
`mpsc::Receiver`'s `recv` future inside the `LocalSet::block_on` call.

## Solution

This branch removes the unnecessary `'static` bound.

Signed-off-by: Eliza Weisman <[email protected]>
2019-12-02 16:43:33 -08:00
Carl Lerche e87df0557d io: add async fns for reading / writing bufs (#1881)
Adds `read_buf` and `write_buf` which work with `T: BufMut` and `T: Buf`
respectively. This adds an easy API for using the buffer traits provided
by `bytes.
2019-12-02 13:09:31 -08:00
Carl Lerche a8a4a9f0fc blocking: fix spawn_blocking after shutdown (#1875)
The task handle needs to be shutdown explicitly and not dropped.

Closes #1853
2019-12-01 12:58:01 -08:00
Carl Lerche 8b60c5386a doc: fix documented feature flags for tokio::task (#1876)
Some feature flags are missing and some are duplicated.

Closes #1836
2019-12-01 12:49:38 -08:00
Carl Lerche af07f5bee7 sync: expand oneshot docs and TryRecvError (#1874)
`oneshot::Receiver::try_recv` does not provide any information as to the
reason **why** receiving failed. The two cases are that the channel is
empty or that the channel closed.

`TryRecvError` is changed to be an enum of those two cases. This is
backwards compatible as `TryRecvError` was an opaque struct.

This also expands on `oneshot` API documentation, adding details and
examples.

Closes #1872
2019-12-01 10:48:47 -08:00
Ivan Petkov 939a0dd7b0 process: rewrite and simplify the issue_42 test (#1871) 2019-11-30 15:17:04 -08:00
Carl Lerche 1ea6733568 io: read/write big-endian numbers (#1863)
Provide convenience methods for encoding and decoding big-endian numbers
on top of asynchronous I/O streams. Only primitive types are provided
(24 and 48 bit numbers are omitted).

In general, using these methods won't be the fastest way to do
encoding/decoding with asynchronous byte streams, but they help to get
simple things working fast.
2019-11-30 13:13:21 -08:00
Carl Lerche 8ce408492a doc: improve AsyncBufReadExt API documentation (#1868)
Remove "old" docs that were left over during a rewrite, add examples and
additional details.
2019-11-30 13:12:39 -08:00
Carl Lerche b559a0cd9a net: expose TcpStream::poll_peek (#1864)
This used to be exposed in 0.1, but was switched to private during the
upgrade. The `async fn` is sufficient for many, but not all cases.

Closes #1556
2019-11-30 09:36:03 -08:00
Carl Lerche 417460cf86 doc: expand mpsc::Sender::send API documentation (#1865)
Includes more description, lists errors, and examples.

Closes #1579
2019-11-30 09:35:23 -08:00
Carl Lerche adaba1a0bc doc: add API docs for AsyncBufReadExt::read_line (#1866)
Include more details and an example.

Closes #1592
2019-11-30 09:34:42 -08:00
Ivan Petkov 467b6ea783 chore: prepare v0.2.2 release (#1857) 2019-11-29 11:09:28 -08:00
Carl Lerche a2cfc877a7 rt: fix basic_scheduler notification bug (#1861)
The "global executor" thread-local is to track where to spawn new tasks,
**not** which scheduler is active on the current thread. This fixes a
bug with scheduling tasks on the basic_scheduler by tracking the
currently active basic_scheduler with a dedicated thread-local variable.

Fixes: #1851
2019-11-29 10:23:22 -08:00
Ömer Sinan Ağacan ec7f2ae306 docs: Mention features for basic_scheduler, threaded_scheduler (#1858)
Fixes #1829
2019-11-29 08:26:58 -08:00
Bartek Iwańczuk 4261ab6627 fs: add File::into_std and File::try_into_std methods (#1856)
In version 0.1 there was File::into_std method that destructured
tokio_fs::File into std::fs:File. That method was lacking in
version 0.2.

Fixes: #1852
2019-11-28 17:09:28 -08:00
Ivan Petkov aef434c089 signal: update documentation with caveats (#1854) 2019-11-28 15:03:04 -08:00
Ömer Sinan Ağacan cd73951130 Implement Stream for signal::unix::Signal (#1849)
Refs #1848
2019-11-28 08:54:50 -08:00
Eliza Weisman 524e66314f task: fix panic when dropping LocalSet (#1843)
It turns out that the `Scheduler::release` method on `LocalSet`'s
`Scheduler` *is* called, when the  `Scheduler` is dropped with tasks
still running. Currently, that method is `unreachable!`, which means
that dropping a `LocalSet` with tasks running will panic.

This commit fixes the panic, by pushing released tasks to
`pending_drop`. This is the same as `BasicScheduler`.

Fixes #1842
2019-11-27 14:24:44 -08:00
Michael Zeller 34d751bf92 net: fix ucred for illumos/solaris (#1772) 2019-11-27 12:22:22 -08:00
Oleg Nosov 942feab040 doc: misc API documentation fixes (#1834) 2019-11-27 12:05:42 -08:00
Oleg Nosov dc356a4158 doc: fix runtime::Builder example (#1841) 2019-11-27 12:03:57 -08:00
Oleg Nosov 2cd1d74092 rt: specify that runtime should have task scheduler (#1839)
* Specify that runtime should have task scheduler

* Even more detailed panic message for incorrect task spawn
2019-11-27 10:25:21 -08:00
Carl Lerche 632ee507ba prepare v0.2.1 release (#1832)
This includes `task::LocalSet` as well as some misc small fixes.
2019-11-26 21:46:02 -08:00
Carl Lerche 7f605ee27f doc: fix and improve incoming() API doc (#1831)
This fixes the API docs for both `TcpListener::incoming` and
`UnixListener::incoming`. The function now takes `&mut self` instead of
`self`. Adds an example for both function.
2019-11-26 21:15:13 -08:00
Eliza Weisman 38e602f4d8 task: add LocalSet API for running !Send futures (#1733)
## Motivation

In earlier versions of `tokio`, the `current_thread::Runtime` type could
be used to run `!Send` futures. However, PR #1716 merged the
current-thread and threadpool runtimes into a single type, which can no
longer run `!Send` futures. There is still a need in some cases to
support futures that don't implement `Send`, and the `tokio-compat`
crate requires this in order to provide APIs that existed in `tokio`
0.1.

## Solution

This branch implements the API described by @carllerche in
https://github.com/tokio-rs/tokio/pull/1716#issuecomment-549496309. It
adds a new `LocalSet` type and `spawn_local` function to `tokio::task`.
The `LocalSet` type is used to group together a set of tasks which must
run on the same thread and don't implement `Send`. These are available
when a new "rt-util" feature flag is enabled.

Currently, the local task set is run by passing it a reference to a
`Runtime` and a future to `block_on`. In the future, we may also want
to investigate allowing spawned futures to construct their own local
task sets, which would be executed on the worker that the future is
executing on. 

In order to implement the new API, I've made some internal changes to
the `task` module and `Schedule` trait to support scheduling both `Send`
and `!Send` futures.

Signed-off-by: Eliza Weisman <[email protected]>
2019-11-26 17:03:18 -08:00
Artem Vorotnikov 8e83a9f2c3 chore: replace Gitter badge with Discord (#1828) 2019-11-26 16:00:38 -08:00
Carl Lerche c146f48f0b fs: impl AsRawFd / AsRawHandle for File (#1827)
This provides the ability to get the raw OS handle for a `File`. The
`Into*` variant cannot be provided as `File` needs to maintain ownership
of the `File`. The actual handle may have been moved to a background
thread.
2019-11-26 16:00:26 -08:00
Benjamin Fry ebf5f37989 time: reexport Elapsed (#1826) 2019-11-26 15:10:41 -08:00
Carl Lerche abfa857f09 chore: remove updating note from readme (#1824) 2019-11-26 10:36:17 -08:00
Carl Lerche a81e2722a4 chore: prepare v0.2.0 release (#1822) 2019-11-26 09:17:27 -08:00
Carl Lerche 4ddc437170 doc: add more doc_cfg annotations (#1821)
Also makes the `tokio::net::{tcp, udp, unix}` modules only for "utility"
types. The primary types are in `tokio::net` directly.
2019-11-25 14:32:55 -08:00
Carl Lerche 3ecaa6d91c docs: improve tokio::io API documentation (#1815)
Adds method level documentation for `tokio::io`.
2019-11-23 08:24:03 -08:00
leo-lb 0bc68adb34 tokio: remove performance regression notice (#1817) 2019-11-23 07:45:56 -08:00
Ivan Petkov e20dff39ce process: do not kill spawned processes on drop (#1814)
This updates the tokio `Command` and `Child` behavior to match that of
the stdlib: spawned processes will *not* be automatically killed when
the handle is dropped

Unlike the stdlib, any dropped (unix) processes may be reaped by tokio
behind-the-scenes after they exit and if new processes are awaited,
which mitigates the risks of piling up unreaped zombie unix processes

A `Command::kill_on_drop` method is added to allow the caller to
control whether the spawned child should be killed when the handle is
dropped. By default, this value is `false`.

The `Child::forget` method has been removed, as it is superseded by
`Command::kill_on_drop`
2019-11-22 20:10:05 -08:00
Carl Lerche 7b4c999341 default all feature flags to off (#1811)
Changes the set of `default` feature flags to `[]`. By default, only
core traits are included without specifying feature flags. This makes it
easier for users to pick the components they need.

For convenience, a `full` feature flag is included that includes all
components.

Tests are configured to require the `full` feature. Testing individual
feature flags will need to be moved to a separate crate.

Closes #1791
2019-11-22 15:55:10 -08:00
Carl Lerche e1b1e216c5 ci: bring back build tests (#1813)
This directory was deleted when `cargo hack` was introduced, however
there were some tests that were still useful (macro failure output).

Also, additional build tests will be added over time.
2019-11-22 14:38:49 -08:00
Taiki Endo 7cd63fb946 ci: use -Z avoid-dev-deps in features check instead of --no-dev-deps (#1812) 2019-11-22 14:13:18 -08:00
Carl Lerche bf741fec35 ci: generate docs (#1810)
Check docs as part of CI. This should catch link errors.
2019-11-22 11:55:57 -08:00
Carl Lerche 9b2aa14bb1 docs: annotate io mod with doc_cfg (#1808)
Annotates types in `tokio::io` module with their required feature flag.
This annotation is included in generated documentation.

Notes:

* The annotation must be on the type or function itself. Annotating just
  the re-export is not sufficient.

* The annotation must be **inside** the `pin_project!` macro or it is
  lost.
2019-11-22 09:56:08 -08:00
Carl Lerche 8546ff826d runtime: cleanup and add config options (#1807)
* runtime: cleanup and add config options

This patch finishes the cleanup as part of the transition to Tokio 0.2.
A number of changes were made to take advantage of having all Tokio
types in a single crate. Also, fixes using Tokio types from
`spawn_blocking`.

* Many threads, one resource driver

Previously, in the threaded scheduler, a resource driver (mio::Poll /
timer combo) was created per thread. This was more or less fine, except
it required balancing across the available drivers. When using a
resource driver from **outside** of the thread pool, balancing is
tricky. The change was original done to avoid having a dedicated driver
thread.

Now, instead of creating many resource drivers, a single resource driver
is used. Each scheduler thread will attempt to "lock" the resource
driver before parking on it. If the resource driver is already locked,
the thread uses a condition variable to park. Contention should remain
low as, under load, the scheduler avoids using the drivers.

* Add configuration options to enable I/O / time

New configuration options are added to `runtime::Builder` to allow
enabling I/O and time drivers on a runtime instance basis. This is
useful when wanting to create lightweight runtime instances to execute
compute only tasks.

* Bug fixes

The condition variable parker is updated to the same algorithm used in
`std`. This is motivated by some potential deadlock cases discovered by
`loom`.

The basic scheduler is fixed to fairly schedule tasks. `push_front` was
accidentally used instead of `push_back`.

I/O, time, and spawning now work from within `spawn_blocking` closures.

* Misc cleanup

The threaded scheduler is no longer generic over `P :Park`. Instead, it
is hard coded to a specific parker. Tests, including loom tests, are
updated to use `Runtime` directly. This provides greater coverage.

The `blocking` module is moved back into `runtime` as all usage is
within `runtime` itself.
2019-11-21 23:28:39 -08:00
Eliza Weisman 6866fe426c docs: expand and update crate-level docs (#1806)
## Motivation

Tokio's crate-level docs are currently pretty sparse, and in some cases
reference old names for APIs. Before 0.2 is released, they could use a
fresh coat of paint.

## Solution

This branch reworks and expands the `lib.rs` docs. In particular, I've
added a new "A Tour of Tokio" section, inspired by the [standard
library's similarly-named section][std]. This section lists all of
`tokio`'s public modules, and summarizes their major APIs. It also lists
the feature flags necessary to enable those APIs.

[std]: https://doc.rust-lang.org/std/index.html#a-tour-of-the-rust-standard-library

Signed-off-by: Eliza Weisman <[email protected]>
2019-11-21 14:09:10 -08:00
Eliza Weisman d88846c4eb docs: update and expand the tokio::runtime API docs (#1804)
## Motivation

The `tokio::runtime` module's docs need to be updated to
track recent changes.

## Solution

This branch updates and expands the `runtime` docs.

Signed-off-by: Eliza Weisman <[email protected]>
2019-11-20 17:46:35 -08:00
Eliza Weisman 7e6a10fccd docs: refresh tokio::io API docs (#1803)
## Motivation

The `tokio::io` module's docs are fairly sparse and not particularly up
to date. They ought to be improved before release.

## Solution

This branch adds new module-level docs to `tokio::io`. The new docs are
largely inspired by `std::io`'s documentation, and highlight the
similarities and differences between `tokio::io` and `std::io`.

Signed-off-by: Eliza Weisman <[email protected]>
2019-11-20 15:09:38 -08:00
Carl Lerche 502cf5d95c io: flatten split module (#1802) 2019-11-20 14:45:38 -08:00
Eliza Weisman c223db3589 docs: improve tokio::task API documentation (#1801)
## Motivation

The new `tokio::task` module is pretty lacking in API docs. 

## Solution

This branch adds new API docs to the `task` module, including:

* Module-level docs with a summary of the differences between 
  tasks and threads
* Examples of how to use the `task` APIs in the module-level docs
* More docs for `yield_now`
* More docs and examples for `JoinHandle`, based on the 
  `std::thread::JoinHandle` API docs.

This branch contains commits cherry-picked from #1794 

Signed-off-by: Eliza Weisman <[email protected]>
2019-11-20 14:36:45 -08:00
Carl Lerche 5cd665afd7 chore: update bytes dependency to git master (#1796)
Tokio will track changes to bytes until 0.5 is released.
2019-11-20 14:27:49 -08:00
Kevin Leimkuhler 3e643c7b81 time: Eagerly bind delays to timer (#1800)
## Motivation

Similar to #1666, it is no longer necessary to lazily register delays with the
executions default timer. All delays are expected to be created from within a
runtime, and should panic if not done so.

## Solution

`tokio::time` now assumes there to be a `CURRENT_TIMER` set when creating a
delay; this can be assumed if called within a tokio runtime. If there is no
current timer, the application will panic with a "no current timer" message.

## Follow-up

Similar to #1666, `HandlePriv` can probably be removed, but this mainly prepares
for 0.2 API changes. Because it is not in the public API, this can be done in a
following change.

Signed-off-by: Kevin Leimkuhler <[email protected]>
2019-11-20 12:24:41 -08:00
Pen Tree bc150cd0b5 Fix doc links (#1799)
Link fix only. After this fix, `cargo doc --package` succeeds.
2019-11-20 12:24:17 -08:00
Carl Lerche 15dce2d11a net: flatten split mod (#1797)
The misc `split` types (`ReadHalf`, `WriteHalf`, `SendHalf`, `RecvHalf`)
are moved up a module and the `*::split` module is removed.
2019-11-20 11:29:32 -08:00
Taiki Endo d4fec2c5d6 chore: enable feature flag check on windows (#1798) 2019-11-20 07:05:50 -08:00
Carl Lerche 69975fb960 Refactor the I/O driver, extracting slab to tokio::util. (#1792)
The I/O driver is made private and moved to `tokio::io::driver`. `Registration` is
moved to `tokio::io::Registration` and `PollEvented` is moved to `tokio::io::PollEvented`.

Additionally, the concurrent slab used by the I/O driver is cleaned up and extracted to
`tokio::util::slab`, allowing it to eventually be used by other types.
2019-11-20 00:05:14 -08:00
Carl Lerche 7c8b8877d4 runtime: fix lost wakeup bug in scheduler (#1788)
When checking if a worker needs to be unparked, the SeqCst load does not
provide the necessary synchronization to ensure the scheduled task is
visible to the searching worker. The `load` is switched to
`fetch_add(0)` which does establish the necessary synchronization.

Adding unit tests catching this bug will require a fix to loom and will
be done at a later time. The bug fix has been validated with manual
testing.

Fixes #1768
2019-11-19 08:01:46 -08:00
Carl Lerche 0d38936b35 chore: refine feature flags (#1785)
Removes dependencies between Tokio feature flags. For example, `process`
should not depend on `sync` simply because it uses the `mpsc` channel.
Instead, feature flags represent **public** APIs that become available
with the feature enabled. When the feature is not enabled, the
functionality is removed. If another Tokio component requires the
functionality, it is stays as `pub(crate)`.

The threaded scheduler is now exposed under `rt-threaded`. This feature
flag only enables the threaded scheduler and does not include I/O,
networking, or time. Those features must be explictly enabled.

A `full` feature flag is added that enables all features.

`stdin`, `stdout`, `stderr` are exposed under `io-std`.

Macros are used to scope code by feature flag.
2019-11-18 07:00:55 -08:00
sclaire-1 13b6e9939e Edit CONTRIBUTING.md (#1784)
Edited the last sentence of the first section to improve clarity
2019-11-17 23:27:42 -08:00
Carl Lerche 44f10fe47f sync: require T: Clone for watch channels. (#1783)
There are limitations with `async/await` (no GAT) requiring the value to
be cloned on receive. The `poll` based API is not currently exposed.
This makes the `Clone` requirement explicit.
2019-11-17 09:03:44 -08:00
Carl Lerche c147be0437 make AtomicWaker private (#1782) 2019-11-16 23:35:17 -08:00
Carl Lerche b1d9e55487 task: move blocking fns into tokio::task (#1781) 2019-11-16 23:35:04 -08:00
Taiki Endo 66cbed3ce3 tls: enable test on CI (#1779) 2019-11-16 22:24:58 -08:00
Carl Lerche 4d19a99937 runtime: set spawn context on enter (#1780) 2019-11-16 22:24:28 -08:00
Taiki Endo 10dc659450 io: expose std{in, out, err} under io feature (#1759)
This exposes `std{in, out, err}` under io feature by moving
`fs::blocking` module into `io::blocking`.
As `fs` feature depends on `io-trait` feature, `fs` implementations can
always access `io` module.
2019-11-16 22:03:39 -08:00
Taiki Endo 320c84a433 chore: migrate from pin-project to pin-project-lite (#1778) 2019-11-16 09:14:40 -08:00
Carl Lerche 19f1fc36bd task: return JoinHandle from spawn (#1777)
`tokio::spawn` now returns a `JoinHandle` to obtain the result of the task:

Closes #887.
2019-11-16 08:28:34 -08:00
Carl Lerche 3f0eabe779 runtime: rename current_thread -> basic_scheduler (#1769)
It no longer supports executing !Send futures. The use case for
It is wanting a “light” runtime. There will be “local” task execution
using a different strategy coming later.

This patch also renames `thread_pool` -> `threaded_scheduler`, but
only in public APIs for now.
2019-11-16 07:19:45 -08:00
Taiki Endo 1474794055 runtime: allow non-unit type output in {Runtime, Spawner}::spawn (#1756) 2019-11-15 22:16:21 -08:00
Taiki Endo 92eb635669 net: add more impls for ToSocketAddrs (#1760) 2019-11-15 22:12:57 -08:00
Carl Lerche 8a7e57786a Limit futures dependency to Stream via feature flag (#1774)
In an effort to reach API stability, the `tokio` crate is shedding its
_public_ dependencies on crates that are either a) do not provide a
stable (1.0+) release with longevity guarantees or b) match the `tokio`
release cadence. Of course, implementing `std` traits fits the
requirements.

The on exception, for now, is the `Stream` trait found in `futures_core`.
It is expected that this trait will not change much and be moved into `std.
Since Tokio is not yet going reaching 1.0, I feel that it is acceptable to maintain
a dependency on this trait given how foundational it is.

Since the `Stream` implementation is optional, types that are logically
streams provide `async fn next_*` functions to obtain the next value.
Avoiding the `next()` name prevents fn conflicts with `StreamExt::next()`.

Additionally, some misc cleanup is also done:

- `tokio::io::io` -> `tokio::io::util`.
- `delay` -> `delay_until`.
- `Timeout::new` -> `timeout(...)`.
- `signal::ctrl_c()` returns a future instead of a stream.
- `{tcp,unix}::Incoming` is removed (due to lack of `Stream` trait).
- `time::Throttle` is removed (due to lack of `Stream` trait).
-  Fix: `mpsc::UnboundedSender::send(&self)` (no more conflict with `Sink` fns).
2019-11-15 22:11:13 -08:00
Markus Westerlind 930679587a codec: Remove Unpin requirement from Framed[Read,Write,] (#1758)
cc #1252
2019-11-15 16:30:07 +09:00
Carl Lerche 27e5b41067 reorganize modules (#1766)
This patch started as an effort to make `time::Timer` private. However, in an
effort to get the build compiling again, more and more changes were made. This
probably should have been broken up, but here we are. I will attempt to
summarize the changes here.

* Feature flags are reorganized to make clearer. `net-driver` becomes
  `io-driver`. `rt-current-thread` becomes `rt-core`.

* The `Runtime` can be created without any executor. This replaces `enter`. It
  also allows creating I/O / time drivers that are standalone.

* `tokio::timer` is renamed to `tokio::time`. This brings it in line with `std`.

* `tokio::timer::Timer` is renamed to `Driver` and made private.

* The `clock` module is removed. Instead, an `Instant` type is provided. This
  type defaults to calling `std::time::Instant`. A `test-util` feature flag can
  be used to enable hooking into time.

* The `blocking` module is moved to the top level and is cleaned up.

* The `task` module is moved to the top level.

* The thread-pool's in-place blocking implementation is cleaned up.

* `runtime::Spawner` is renamed to `runtime::Handle` and can be used to "enter"
  a runtime context.
2019-11-12 15:23:40 -08:00
Anton Barkovsky e3df2eafd3 tls: fix test certificate to work on macOS 10.15 (#1763)
macOS 10.15 introduced new requirements for certificates to be trusted:
https://support.apple.com/en-us/HT210176
2019-11-11 12:09:14 +01:00
Taiki Endo c15e01a09b chore: remove rust-toolchain and add minimum supported version check (#1748)
* remove rust-toolchain

* add minimum supported version check
2019-11-08 13:26:08 +09:00
Taiki Endo 64f2bf0072 chore: update CI config to test on stable (#1747) 2019-11-08 00:32:04 +09:00
Carl Lerche 7e35922a1d time: rename tokio::timer -> tokio::time (#1745) 2019-11-06 23:53:46 -08:00
Carl Lerche 4dbe6af0a1 runtime: misc pool cleanup (#1743)
- Remove builders for internal types
- Avoid duplicating the blocking pool when using the concurrent
  scheduler.
- misc smaller cleanup
2019-11-06 21:29:10 -08:00
leo-lb 9bec094150 timer: have example use delay_for instead of delay (#1735)
It is a more common use case that is to simply cause a delay for an amount of time.
I think it is more appropriate to show off `delay_for` in the example rather than `delay` that is useful only for less common use cases.
2019-11-06 21:28:21 -08:00
Taiki Endo 6f8b986bdb chore: update futures to 0.3.0 (#1741) 2019-11-07 05:09:10 +09:00
Carl Lerche 1a7f6fb201 simplify enter (#1736) 2019-11-06 09:51:15 -08:00
Carl Lerche 0da23aad77 fix clippy (#1737) 2019-11-05 23:38:52 -08:00
Carl Lerche d5c1119c88 runtime: combine executor and runtime mods (#1734)
Now, all types are under `runtime`. `executor::util` is moved to a top
level `util` module.
2019-11-05 19:12:30 -08:00
Carl Lerche a6253ed05a chore: unify all mocked loom files (#1732)
When the crates were merged, each component kept its own `loom` file
containing mocked types it needed. This patch unifies them all in one
location.
2019-11-04 22:22:40 -08:00
Carl Lerche 94f9b04b06 executor: switch some APIs to crate private. (#1731)
* switch `enter` to crate private
* make executor types pub(crate)
2019-11-04 14:12:24 -08:00
Carl Lerche 966ccd5d53 test: unify MockTask and task::spawn (#1728)
Delete `MockTask` in favor of `task::spawn`. Both are functionally
equivalent.
2019-11-03 14:10:14 -08:00
Taiki Endo 3948e16292 ci: install minimal profile by default (#1729) 2019-11-03 12:08:07 -08:00
Sebastian Dröge 6b35a1e8b0 impl AsyncWrite for std::io::Cursor (#1730)
Based on the implementation from the futures crate.
2019-11-03 21:21:01 +09:00
Carl Lerche e19bd77ef0 tests: fix bug + reorganize tests. (#1726)
Fixes a bug in the thread-pool executor related to shutdown
concurrent with a task that is self-notifying. A `loom` test is
added to validate the fix.

Additionally, in anticipation of the `thread_pool` module being
switched to private, tests are updated to use `Runtime` directly
instead of `thread_pool`. Those tests that cannot be updated
are switched to unit tests.
2019-11-02 17:03:06 -07:00
Carl Lerche c8fdbed27a chore: prune dev-dependencies
Most dev dependendencies are unused now that examples are moved into a
separate crate.
2019-11-02 09:40:37 +01:00
Carl Lerche 3e7d0be51d executor: remove Executor & TypedExecutor traits (#1724)
The `Executor` trait is sub-optimal as it forces a `Box<dyn Future>` to
spawn. Instead, `tokio::spawn` delegates to the specific runtime
implementation set for the current execution context.

`TypedExecutor`, while useful, has seen limited adoption. As such, it is
removed from `tokio` proper. Moving it to `tokio-util` is a possibility
that can be explored as follow up work.
2019-11-01 13:50:17 -07:00
Carl Lerche d70c928d88 runtime: merge multi & single threaded runtimes (#1716)
Simplify Tokio's runtime construct by combining both Runtime variants
into a single type. The execution style can be controlled by a
configuration setting on `Builder`.

The implication of this change is that there is no longer any way to
spawn `!Send` futures. This, however, is a temporary limitation. A
different strategy will be employed for supporting `!Send` futures.

Included in this patch is a rework of `task::JoinHandle` to support
using this type from both the thread-pool and current-thread executors.
2019-11-01 13:18:52 -07:00
Steven Fackler 742d89b0f3 Fix delay construction from non-lazy Handles (#1720)
Closes #1719.
2019-11-01 12:32:57 -07:00
Carl Lerche 20993341bd compat: extract crate to a dedicated git repo (#1723)
The compat crate is moved to https://github.com/tokio-rs/tokio-compat.
This allows pinning it to specific revisions of the Tokio git
repository. The master branch is intended to go through significant
churn and it will be easier to update the compat layer in batches.
2019-11-01 12:30:12 -07:00
Eliza Weisman e699d46534 compat: add a compat runtime (#1663)
## Motivation

The `futures` crate's [`compat` module][futures-compat] provides
interoperability between `futures` 0.1 and `std::future` _future types_
(e.g. implementing `std::future::Future` for a type that implements the
`futures` 0.1 `Future` trait). However, this on its own is insufficient
to run code written against `tokio` 0.1 on a `tokio` 0.2 runtime, if
that code also relies on `tokio`'s runtime services. If legacy tasks are
executed that rely on `tokio::timer`, perform IO using `tokio`'s
reactor, or call `tokio::spawn`, those API calls will fail unless there
is also a runtime compatibility layer.

## Solution

As proposed in #1549, this branch introduces a new `tokio-compat` crate,
with implementations of the thread pool and current-thread runtimes that
are capable of running both tokio 0.1 and tokio 0.2 tasks. The compat
runtime creates a background thread that runs a `tokio` 0.1 timer and
reactor, and sets itself as the `tokio` 0.1 executor as well as the
default 0.2 executor. This allows 0.1 futures that use 0.1 timer,
reactor, and executor APIs may run alongside `std::future` tasks on the
0.2 runtime.

### Examples

Spawning both `tokio` 0.1 and `tokio` 0.2 futures:

```rust
use futures_01::future::lazy;

tokio_compat::run(lazy(|| {
    // spawn a `futures` 0.1 future using the `spawn` function from the
    // `tokio` 0.1 crate:
    tokio_01::spawn(lazy(|| {
        println!("hello from tokio 0.1!");
        Ok(())
    }));

    // spawn an `async` block future on the same runtime using `tokio`
    // 0.2's `spawn`:
    tokio_02::spawn(async {
        println!("hello from tokio 0.2!");
    });

    Ok(())
}))
```

Futures on the compat runtime can use `timer` APIs from both 0.1 and 0.2
versions of `tokio`:

```rust
use std::time::{Duration, Instant};
use futures_01::future::lazy;
use tokio_compat::prelude::*;

tokio_compat::run_03(async {
    // Wait for a `tokio` 0.1 `Delay`...
    let when = Instant::now() + Duration::from_millis(10);
    tokio_01::timer::Delay::new(when)
        // convert the delay future into a `std::future` that we can `await`.
        .compat()
        .await
        .expect("tokio 0.1 timer should work!");
    println!("10 ms have elapsed");

    // Wait for a `tokio` 0.2 `Delay`...
    let when = Instant::now() + Duration::from_millis(20);
    tokio_02::timer::delay(when).await;
    println!("20 ms have elapsed");
});
```

## Future Work

This is just an initial implementation of a `tokio-compat` crate; there
are more compatibility layers we'll want to provide before that crate is
complete. For example, we should also provide compatibility between
`tokio` 0.2's `AsyncRead` and `AsyncWrite` traits and the `futures` 0.1
and `futures` 0.3 versions of those traits. In #1549, @carllerche also
suggests that the `compat` crate provide reimplementations of APIs that
were removed from `tokio` 0.2 proper, such as the `tcp::Incoming`
future.

Additionally, there is likely extra work required to get the 
`tokio-threadpool` 0.1 `blocking` APIs to work on the compat runtime.
This will be addressed in a follow-up PR.

Fixes: #1605
Fixes: #1552
Refs: #1549

[futures-compat]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.19/futures/compat/index.html
2019-11-01 10:35:02 -07:00
Carl Lerche 72caede7be chore: remove dead files (#1718)
The `codec` module has been moved to `tokio-util`. Some files were left,
but they were never activated.
2019-11-01 21:30:06 +09:00
Carl Lerche 64c26ab1ee runtime: test creating a single-threaded runtime. (#1717) 2019-10-31 22:28:31 -07:00
Taiki Endo 02f7264008 chore: check each feature works properly (#1695)
It is hard to maintain features list manually, so use cargo-hack's
`--each-feature` flag. And cargo-hack provides a workaround for an issue
that dev-dependencies leaking into normal build (`--no-dev-deps` flag),
so removed own ci tool.

Also, compared to running tests on all features, there is not much
advantage in running tests on each feature, so only the default features
and all features are tested.
If the behavior changes depending on the feature, we need to test it as
another job in CI.
2019-10-31 21:09:32 -07:00
Jonathan Bastien-Filiatrault 2902e39db0 Allow non-destructive access to the read buffer. (#1600)
I need this to implement SMTP pipelining checks. I mostly need to
flush my send buffer when the read buffer is empty before waiting for
the next command.
2019-10-31 10:36:24 -04:00
Steven Fackler 630d3136dd timere: make Delay must_use (#1714)
Closes #1711
2019-10-30 20:21:03 -07:00
Sean McArthur 2c870b588f process: refactor OrphanQueue to use a Mutex instead fo SegQueue (#1712) 2019-10-30 15:29:04 -07:00
Jon Gjengset 109fd3086b thread-pool: in-place blocking with new scheduler (#1681)
The initial new scheduler PR omitted in-place blocking
support. This patch brings it back.
2019-10-30 08:58:49 -07:00
Sean McArthur e3261440e5 timer: inline CachePadded type (#1706) 2019-10-29 22:16:11 -07:00
Carl Lerche 2b909d6805 sync: move into tokio crate (#1705)
A step towards collapsing Tokio sub crates into a single `tokio`
crate (#1318).

The sync implementation is now provided by the main `tokio` crate.
Functionality can be opted out of by using the various net related
feature flags.
2019-10-29 15:11:31 -07:00
Carl Lerche c62ef2d232 executor: move into tokio crate (#1702)
A step towards collapsing Tokio sub crates into a single `tokio`
crate (#1318).

The executor implementation is now provided by the main `tokio` crate.
Functionality can be opted out of by using the various net related
feature flags.
2019-10-28 21:40:29 -07:00
Eliza Weisman 7eb264a0d0 net: replace RwLock<Slab> with a lock free slab (#1625)
## Motivation

The `tokio_net::driver` module currently stores the state associated
with scheduled IO resources in a `Slab` implementation from the `slab`
crate. Because inserting items into and removing items from `slab::Slab`
requires mutable access, the slab must be placed within a `RwLock`. This
has the potential to be a performance bottleneck especially in the context of
the work-stealing scheduler where tasks and the reactor are often located on
the same thread.

`tokio-net` currently reimplements the `ShardedRwLock` type from
`crossbeam` on top of `parking_lot`'s `RwLock` in an attempt to squeeze
as much performance as possible out of the read-write lock around the
slab. This introduces several dependencies that are not used elsewhere.

## Solution

This branch replaces the `RwLock<Slab>` with a lock-free sharded slab
implementation. 

The sharded slab is based on the concept of _free list sharding_
described by Leijen, Zorn, and de Moura in [_Mimalloc: Free List
Sharding in Action_][mimalloc], which describes the implementation of a
concurrent memory allocator. In this approach, the slab is sharded so
that each thread has its own thread-local list of slab _pages_. Objects
are always inserted into the local slab of the thread where the
insertion is performed. Therefore, the insert operation needs not be
synchronized.

However, since objects can be _removed_ from the slab by threads other
than the one on which they were inserted, removal operations can still
occur concurrently. Therefore, Leijen et al. introduce a concept of
_local_ and _global_ free lists. When an object is removed on the same
thread it was originally inserted on, it is placed on the local free
list; if it is removed on another thread, it goes on the global free
list for the heap of the thread from which it originated. To find a free
slot to insert into, the local free list is used first; if it is empty,
the entire global free list is popped onto the local free list. Since
the local free list is only ever accessed by the thread it belongs to,
it does not require synchronization at all, and because the global free
list is popped from infrequently, the cost of synchronization has a
reduced impact. A majority of insertions can occur without any
synchronization at all; and removals only require synchronization when
an object has left its parent thread.

The sharded slab was initially implemented in a separate crate (soon to
be released), vendored in-tree to decrease `tokio-net`'s dependencies.
Some code from the original implementation was removed or simplified,
since it is only necessary to support `tokio-net`'s use case, rather
than to provide a fully generic implementation.

[mimalloc]: https://www.microsoft.com/en-us/research/uploads/prod/2019/06/mimalloc-tr-v1.pdf

## Performance

These graphs were produced by out-of-tree `criterion` benchmarks of the
sharded slab implementation.


The first shows the results of a benchmark where an increasing number of
items are inserted and then removed into a slab concurrently by five
threads. It compares the performance of the sharded slab implementation
with a `RwLock<slab::Slab>`:

<img width="1124" alt="Screen Shot 2019-10-01 at 5 09 49 PM" src="https://user-images.githubusercontent.com/2796466/66078398-cd6c9f80-e516-11e9-9923-0ed6292e8498.png">

The second graph shows the results of a benchmark where an increasing
number of items are inserted and then removed by a _single_ thread. It
compares the performance of the sharded slab implementation with an
`RwLock<slab::Slab>` and a `mut slab::Slab`.

<img width="925" alt="Screen Shot 2019-10-01 at 5 13 45 PM" src="https://user-images.githubusercontent.com/2796466/66078469-f0974f00-e516-11e9-95b5-f65f0aa7e494.png">

Note that while the `mut slab::Slab` (i.e. no read-write lock) is
(unsurprisingly) faster than the sharded slab in the single-threaded
benchmark, the sharded slab outperforms the un-contended
`RwLock<slab::Slab>`. This case, where the lock is uncontended and only
accessed from a single thread, represents the best case for the current
use of `slab` in `tokio-net`, since the lock cannot be conditionally
removed in the single-threaded case.

These benchmarks demonstrate that, while the sharded approach introduces
a small constant-factor overhead, it offers significantly better
performance across concurrent accesses.

## Notes

This branch removes the following dependencies `tokio-net`:
- `parking_lot`
- `num_cpus`
- `crossbeam_util`
- `slab`

This branch adds the following dev-dependencies:
- `proptest`
- `loom`

Note that these dev dependencies were used to implement tests for the
sharded-slab crate out-of-tree, and were necessary in order to vendor
the existing tests. Alternatively, since the implementation is tested
externally, we _could_ remove these tests in order to avoid picking up
dev-dependencies. However, this means that we should try to ensure that
`tokio-net`'s vendored implementation doesn't diverge significantly from
upstream's, since it would be missing a majority of its tests.

Signed-off-by: Eliza Weisman <[email protected]>
2019-10-28 11:30:45 -07:00
Geoff Shannon 1195263584 Fix docs links: Redux (#1698) 2019-10-27 09:37:07 -07:00
Carl Lerche bccb713d98 thread-pool: test additional shutdown cases (#1697)
This adds an extra spawned task during the thread-pool shutdown loom
test. This results in additional cases being tested, primarily tasks
being stolen.
2019-10-26 22:15:39 -07:00
Linus Färnstrand 474befd23c chore: use argument position impl trait (#1690) 2019-10-26 08:40:38 -07:00
Carl Lerche 987ba7373c io: move into tokio crate (#1691)
A step towards collapsing Tokio sub crates into a single `tokio`
crate (#1318).

The `io` implementation is now provided by the main `tokio` crate.
Functionality can be opted out of by using the various net related
feature flags.
2019-10-26 08:02:49 -07:00
Carl Lerche 227533d456 net: move into tokio crate (#1683)
A step towards collapsing Tokio sub crates into a single `tokio`
crate (#1318).

The `net` implementation is now provided by the main `tokio` crate.
Functionality can be opted out of by using the various net related
feature flags.
2019-10-25 12:50:15 -07:00
Jon Gjengset 03a9378297 Make blocking pool non-static and use for thread pool (#1678)
Previously, support for `blocking` was done through a static `POOL` that
would spawn threads on demand. While this made the pool accessible at
all times, it made it hard to configure, and it was impossible to keep
multiple blocking pools.

This patch changes `blocking` to instead use a "default" global like the
ones used for timers, executors, and the like. There is now
`blocking::with_pool`, which is used by both thread-pool workers and the
current-thread runtime to ensure that a pool is available to tasks.

This patch also changes `ThreadPool` to spawn its worker threads on the
blocking pool rather than as free-standing threads. This is in
preparation for the coming in-place blocking work.

One downside of this change is that thread names are no longer
"semantic". All threads are named by the pool name, and individual
threads are not (currently) given names with numerical suffixes like
before.
2019-10-24 14:17:47 -07:00
Carl Lerche 99940aeeb4 chore: remove tracing. (#1680)
Historically, logging has been added haphazardly. Here, we entirely
remove logging as none of it is particularly useful. In the future, we
will add tracing back in order to expose useful data to the user of
Tokio.
2019-10-23 11:04:14 -07:00
Carl Lerche cfc15617a5 codec: move into tokio-util (#1675)
Related to #1318, Tokio APIs that are "less stable" are moved into a new
`tokio-util` crate. This crate will mirror `tokio` and provide
additional APIs that may require a greater rate of breaking changes.

As examples require `tokio-util`, they are moved into a separate
crate (`examples`). This has the added advantage of being able to avoid
example only dependencies in the `tokio` crate.
2019-10-22 10:13:49 -07:00
Carl Lerche b8cee1a60a timer: move tokio-timer into tokio crate (#1674)
A step towards collapsing Tokio sub crates into a single `tokio`
crate (#1318).

The `timer` implementation is now provided by the main `tokio` crate.
The `timer` functionality may still be excluded from the build by
skipping the `timer` feature flag.
2019-10-21 16:45:13 -07:00
Kevin Leimkuhler c9bcbe77b9 net: Eagerly bind resources to reactors (#1666)
## Motivation

The `tokio_net` resources can be created outside of a runtime due to how tokio
has been used with futures to date. For example, this allows a `TcpStream` to be
created, and later passed into a runtime:

```
let stream = TcpStream::connect(...).and_then(|socket| {
    // do something
});
tokio::run(stream);
```

In order to support this functionality, the reactor was lazily bound to the
resource on the first call to `poll_read_ready`/`poll_write_ready`. This
required a lot of additional complexity in the binding logic to support.

With the tokio 0.2 common case, this is no longer necessary and can be removed.
All resources are expected to be created from within a runtime, and should panic
if not done so.

Closes #1168

## Solution

The `tokio_net` crate now assumes there to be a `CURRENT_REACTOR` set on the
worker thread creating a resource; this can be assumed if called within a tokio
runtime. If there is no current reactor, the application will panic with a "no
current reactor" message.

With this assumption, all the unsafe and atomics have been removed from
`tokio_net::driver::Registration` as it is no longer needed.

There is no longer any reason to pass in handles to the family of `from_std` methods on `net` resources. `Handle::current` has therefore a more restricted private use where it is only used in `driver::Registration::new`.

Signed-off-by: Kevin Leimkuhler <[email protected]>
2019-10-21 16:20:06 -07:00
Carl Lerche 978013a215 fs: move into tokio (#1672)
A step towards collapsing Tokio sub crates into a single `tokio`
crate (#1318).

The `fs` implementation is now provided by the main `tokio` crate. The
`fs` functionality may still be excluded from the build by skipping the
`fs` feature flag.
2019-10-21 15:49:00 -07:00
madmaxio 6aa6ebb5bc io: Take struct re-export to main crate (#1670) 2019-10-21 10:03:05 -07:00
Jonathas Conceição 4bee94eb06 runtime: update doc regarding runtime::run function helper (#1671) 2019-10-21 10:02:36 -07:00
Carl Lerche ed5a94eb2d executor: rewrite the work-stealing thread pool (#1657)
This patch is a ground up rewrite of the existing work-stealing thread
pool. The goal is to reduce overhead while simplifying code when
possible.

At a high level, the following architectural changes were made:

- The local run queues were switched for bounded circle buffer queues.
- Reduce cross-thread synchronization.
- Refactor task constructs to use a single allocation and always include
  a join handle (#887).
- Simplify logic around putting workers to sleep and waking them up.

**Local run queues**

Move away from crossbeam's implementation of the Chase-Lev deque. This
implementation included unnecessary overhead as it supported
capabilities that are not needed for the work-stealing thread pool.
Instead, a fixed size circle buffer is used for the local queue. When
the local queue is full, half of the tasks contained in it are moved to
the global run queue.

**Reduce cross-thread synchronization**

This is done via many small improvements. Primarily, an upper bound is
placed on the number of concurrent stealers. Limiting the number of
stealers results in lower contention. Secondly, the rate at which
workers are notified and woken up is throttled. This also reduces
contention by preventing many threads from racing to steal work.

**Refactor task structure**

Now that Tokio is able to target a rust version that supports
`std::alloc` as well as `std::task`, the pool is able to optimize how
the task structure is laid out. Now, a single allocation per task is
required and a join handle is always provided enabling the spawner to
retrieve the result of the task (#887).

**Simplifying logic**

When possible, complexity is reduced in the implementation. This is done
by using locks and other simpler constructs in cold paths. The set of
sleeping workers is now represented as a `Mutex<VecDeque<usize>>`.
Instead of optimizing access to this structure, we reduce the amount the
pool must access this structure.

Secondly, we have (temporarily) removed `threadpool::blocking`. This
capability will come back later, but the original implementation was way
more complicated than necessary.

**Results**

The thread pool benchmarks have improved significantly:

Old thread pool:

```
test chained_spawn ... bench:   2,019,796 ns/iter (+/- 302,168)
test ping_pong     ... bench:   1,279,948 ns/iter (+/- 154,365)
test spawn_many    ... bench:  10,283,608 ns/iter (+/- 1,284,275)
test yield_many    ... bench:  21,450,748 ns/iter (+/- 1,201,337)
```

New thread pool:

```
test chained_spawn ... bench:     147,943 ns/iter (+/- 6,673)
test ping_pong     ... bench:     537,744 ns/iter (+/- 20,928)
test spawn_many    ... bench:   7,454,898 ns/iter (+/- 283,449)
test yield_many    ... bench:  16,771,113 ns/iter (+/- 733,424)
```

Real-world benchmarks improve significantly as well. This is testing the hyper hello
world server using: `wrk -t1 -c50 -d10`:

Old scheduler:

```
Running 10s test @ http://127.0.0.1:3000
  1 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   371.53us   99.05us   1.97ms   60.53%
    Req/Sec   114.61k     8.45k  133.85k    67.00%
  1139307 requests in 10.00s, 95.61MB read
Requests/sec: 113923.19
Transfer/sec:      9.56MB
```

New scheduler:

```
Running 10s test @ http://127.0.0.1:3000
  1 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   275.05us   69.81us   1.09ms   73.57%
    Req/Sec   153.17k    10.68k  171.51k    71.00%
  1522671 requests in 10.00s, 127.79MB read
Requests/sec: 152258.70
Transfer/sec:     12.78MB
```
2019-10-19 11:09:40 -07:00
Steven Fackler 2a181320b7 fs: add read_to_string (#1664) 2019-10-16 15:47:37 -07:00
Taiki Endo 4c97e9dc28 fs: remove unnecessary trait and lifetime bounds (#1655) 2019-10-15 19:02:34 +09:00
Jon Gjengset 1cae04f8b3 macros: Use more consistent runtime names (#1628)
As discussed in #1620, the attribute names for `#[tokio::main]` and
`#[tokio::test]` aren't great. Specifically, they both use
`single_thread` and `multi_thread`, as opposed to names that match the
runtime names: `current_thread` and `threadpool`. This PR changes the
former to the latter.

Fixes #1627.
2019-10-12 12:55:39 -04:00
John-John Tedro 29f35df7f8 Remove incorrect FusedFuture impl on Delay (#1652)
`is_terminated` must return `true` until the future has been polled at least once to make sure that the associated block in select is called even after the delay has elapsed.

You use `Delay` in a `select!` by [fusing it](https://docs.rs/futures-preview/0.3.0-alpha.19/futures/future/trait.FutureExt.html#method.fuse):

```rust
let delay = tokio::timer::delay(/* ... */);
let delay = delay.fuse();

select! {
    _ = delay => {
        /* work here */
    }
}
```
2019-10-11 15:45:44 -04:00
Ivan Petkov 741bef8fe1 tokio: move signal and process reexports to crate root (#1643) 2019-10-11 11:00:39 -07:00
Carl Lerche 804dbd6f8e sync: fix mem leak in oneshot on task migration (#1648)
When polling the task, the current waker is saved to the oneshot state.
When the handle is migrated to a new task and polled again, the waker
must be swaped from the old waker to the new waker. In some cases, there
is a potential for the old waker to leak.

This bug was caught by loom with the recently added memory leak
detection.
2019-10-10 12:00:22 -07:00
Eliza Weisman 69fe65e972 io: add AsyncBufReadExt::split (#1642)
add a `split` method to `AsyncBufReadExt`, analogous to `std::io::BufRead::split`.
2019-10-09 13:17:07 -07:00
Jonathan Bastien-Filiatrault b8913ec7c0 executor: accurate idle thread tracking for the blocking pool (#1621)
Use a counter to count notifications. This protects against spurious
wakeups by pthreads and other libraries. The state transitions now
track num_idle precisely.
2019-10-07 14:04:28 -07:00
Eliza Weisman 8aa520e2bd io: add missing utility functions (#1632)
The standard library's `io` module has small utilities such as `repeat`,
`empty`, and `sink`, which return `Read` and `Write` implementations.
These can come in handy in some circiumstances. `tokio::io` has no
equivalents that implement `AsyncRead`/`AsyncWrite`.

This commit adds `repeat`, `empty`, and `sink` helpers to `tokio::io`.
2019-10-07 14:02:04 -07:00
Nick Stott ab2f71a612 chore: fix a comment typo (#1633) 2019-10-07 09:20:57 -07:00
Taiki Endo 42a5cb1508 timer: test arm on targets with target_has_atomic less than 64 (#1634) 2019-10-07 09:19:44 -07:00
Taiki Endo 2b4b0619d7 chore: update Cirrus CI config to test on beta (#1636) 2019-10-07 09:18:38 -07:00
Taiki Endo 55caddb9ce chore: do not trigger CI on std-future branch (#1635) 2019-10-07 09:17:27 -07:00
Vojtech Kral aefaef3abf tcp: export Incoming type (#1602) 2019-10-02 11:12:05 -07:00
Jon Gjengset c78c9168d7 macros: allow selecting runtime in tokio::test attr (#1620)
In the past, it was not possible to choose to use the multi-threaded
tokio `Runtime` in tests, which meant that any test that transitively
used `executor::threadpool::blocking` would fail with

```
'blocking' annotation used from outside the context of a thread pool
```

This patch adds a runtime annotation attribute to `#[tokio::test]` just
like `#[tokio::main]` has, which lets users opt in to the threadpool
runtime over `current_thread` (the default).
2019-10-02 10:58:34 -07:00
Jonathan Bastien-Filiatrault 9e1eef829a chore: annotate prelude re-exports as doc(no_inline) (#1601)
Fixes #1593 by making "use as _" linked in the documentation.
2019-10-02 10:55:35 -07:00
Taiki Endo f48980ae52 chore: update rust-toolchain to use beta (#1619) 2019-10-01 10:13:38 -04:00
Douman a1d1eb5eb3 macros: Allow arguments in non-main functions 2019-10-01 13:15:46 +02:00
Jon Gjengset 5efe31f2ed Prepare for release of 0.2.0-alpha.6 (#1617)
Note that `tokio-timer` and `tokio-tls` become 0.3.0-alpha.6 (not 0.2.0)
2019-09-30 18:35:52 -04:00
Jon Gjengset 5ce5a0a0e0 Fix for rust-lang/rust#64477 (#1618)
`foo(format!(...)).await` no longer compiles. There's a fix in
rust-lang/rust#64856, but this works around the problem.
2019-09-30 17:17:14 -04:00
Jon Gjengset 5fd5329497 Create BufStream from a BufReader + BufWriter (#1609)
This is handy if developers want to construct the inner buffers with a
particular capacity, and still end up with a `BufStream` at the end.
2019-09-30 14:22:59 -04:00
Taiki Endo 3b8ee2d991 chore: update futures-preview to 0.3.0-alpha.19 (#1610) 2019-09-30 13:32:37 -04:00
Jon Gjengset 7c341f45e0 chore: move CI to beta (#1615) 2019-09-27 09:51:45 -07:00
Jon Gjengset 611b4e11a7 Make Barrier::wait future Send (#1611)
It wasn't before. Now it is. And that is better.
2019-09-26 18:26:24 -04:00
Taiki Endo 159abb375f chore: update pin-project to 0.4 (#1603) 2019-09-27 04:51:28 +09:00
Carl Lerche 032b39487c sync: add spin_loop_hint to atomic waker (#1608)
The algorithm backing `AtomicWaker` effectively uses a spin lock backed
by notifying & yielding the current task. This adds a `spin_lock_hint`
annotation to cover this case.

While, in practice, the omission of `spin_lock_hint` would not cause
problems, there are platforms that do not handle spin locks very well
and could enter a deadlock in pathological cases.
2019-09-26 15:16:34 -04:00
Hung-I Wang b71b7b36be fs: update the doc comment of File::sync_data (#1596) 2019-09-25 09:05:50 -07:00
Taiki Endo c4567f741a io: add get_*/into_inner methods to BufStream (#1598) 2019-09-25 09:17:43 -04:00
Sean McArthur 18cef1901f tokio: add rt-current-thread optional feature
- Adds a minimum `rt-current-thread` optional feature that exports
  `tokio::runtime::current_thread`.
- Adds a `macros` optional feature to enable the `#[tokio::main]` and
  `#[tokio::test]` attributes.
- Adjusts `#[tokio::main]` macro to select a runtime "automatically" if
  a specific strategy isn't specified. Allows using the macro with only
  the rt-current-thread feature.
2019-09-24 12:17:04 -07:00
Taiki Endo c81447fdcc io: remove unsafe pin-projections and remove manual Unpin implementations (#1588)
* Removes most pin-projection related unsafe code.

* Removes manual Unpin implementations.
  As references always implement Unpin, there is no need to implement
  Unpin manually.

* Adds tests to check that Unpin requirement does not change accidentally 
  because changing Unpin requirements will be breaking changes.
2019-09-25 01:17:06 +09:00
Taiki Endo d50d050fae net: fix build-tests for uds (#1589) 2019-09-24 02:47:39 +09:00
Taiki Endo 3a55aba251 macros: add build tests for #[tokio::main] and #[tokio::test] (#1591) 2019-09-23 04:09:30 +09:00
Taiki Endo ddbb0c3836 macros: fix handling of arguments of #[tokio::main] attribute (#1578) 2019-09-23 03:05:04 +09:00
Taiki Endo 376d63867a chore: update pin-project to 0.4.0-beta.1 (#1586) 2019-09-23 01:52:14 +09:00
Taiki Endo eb2d0fbcd1 net: use Box::pin instead of Pin::new(Box::new) (#1587) 2019-09-22 09:28:55 -07:00
Jonathan Bastien-Filiatrault 695165feac timer: 32 bit ARM only has 32 bit atomics. (#1581) 2019-09-20 13:25:49 -07:00
Kirill Mironov ff186a4d03 tokio: add process feature (#1561) 2019-09-19 19:03:58 -07:00
Jon Gjengset 6611b32cce Export sync::Barrier from tokio::sync (#1577) 2019-09-19 21:32:35 -04:00
Carl Lerche 80ba2a4ff6 Release 0.2.0 alpha.5 (#1576) 2019-09-19 13:39:35 -07:00
Carl Lerche 8d09f61d33 net: fix build with only process (#1575) 2019-09-19 12:38:15 -07:00
Carl Lerche 815173f8e5 chore: rm tokio-buf (#1574)
The crate has not been updated and it does not seem like it is a good
path forward.
2019-09-19 12:11:21 -07:00
Markus Westerlind 34e388619f timer: delay_for should use tokio_timer::clock::now (#1572) 2019-09-19 11:20:18 -07:00
Jon Gjengset 9d5af20bcf Enable buffering both reads and writes (#1558)
`BufWriter` and `BufReader` did not previously forward the "opposite" trait (`AsyncRead` for `BufWriter` and `AsyncWrite` for `BufReader`). This meant that there was no way to have both directions buffered at once. This patch fixes that, and introduces a convenience type + constructor for this double-wrapped construct.
2019-09-19 14:17:15 -04:00
Jon Gjengset 613fde2637 sync: add Barrier primitive (#1571)
This adds `Barrier` to `tokio-sync`, which is an asynchronous alternative to [`std::sync::Barrier`](https://doc.rust-lang.org/std/sync/struct.Barrier.html). It is a synchronization primitive that allows multiple futures to "rendezvous" at certain points in their execution.
2019-09-19 14:16:56 -04:00
Jonathan Bastien-Filiatrault 22a3b10171 executor: fix blocking pool bug re: thread shutdown (#1562)
Currently, when threads in the blocking pool shutdown due to being idle
the counter tracking threads is not decremented. This prevents new threads
from being spawned to replace the shutdown threads.
2019-09-19 11:12:04 -07:00
Jon Gjengset e3415d8d61 sync: Make Lock more similar to std::sync::Mutex (#1573)
This renames `Lock` to `Mutex`, and brings the API more in line with `std::sync::Mutex`.

In partcular, locking now only takes `&self`, with the expectation that you place the `Mutex` in an `Arc` (or something similar) to share it between threads.

Fixes #1544.
Part of #1210.
2019-09-19 11:46:52 -04:00
Taiki Endo d1f60ac4c6 chore: deny warnings for doc tests (#1539) 2019-09-19 15:50:12 +09:00
Taiki Endo e2161502ad chore: fix clippy check failure (#1569) 2019-09-18 10:19:44 -07:00
yjh ab785bfba7 Update README.md (#1545)
change url's `version` to `latest`.
2019-09-17 10:54:22 -04:00
Lucio Franco 5f2f3f076d Add broken feature to old benchmarks (#1555)
Signed-off-by: Lucio Franco <[email protected]>
2019-09-13 14:04:23 -04:00
Taiki Endo efb27731ad timer: use our own AtomicU64 on targets with target_has_atomic less than 64 (#1538) 2019-09-13 10:18:32 -07:00
cynecx 578a9aec16 sync: replace deprecated mem::uninitialized usage with MaybeUninit (#1540) 2019-09-13 10:03:03 -07:00
Jonathan Bastien-Filiatrault 5b8fc19701 fs: propagate flush for stdout / stderr. (#1528) 2019-09-13 09:58:18 -07:00
Geoff Shannon c0a64d67ca chore: fix docs links (#1523) 2019-09-13 09:46:19 -07:00
Carl Lerche 6369d0f4f2 chore: add stability note to readme. (#1554) 2019-09-13 09:12:30 -07:00
Kirill Mironov f69ee652e6 tls: fix new temporary lifetime rustc error [E0597] (#1547)
Fixes: #1546
Signed-off-by: Kirill Mironov <[email protected]>
2019-09-11 10:22:04 -07:00
Jon Gjengset 9b3f8564af tls: Add get_ref and get_mut (#1537) 2019-09-04 17:45:53 -04:00
Ivan Petkov 9766cd644f process: omit several future types in favor of async/await (#1526) 2019-08-31 13:02:27 -07:00
Carl Lerche 431d4857e8 io: add Send / Sync impls for ReadHalf / WriteHalf (#1525) 2019-08-31 12:18:55 -07:00
Fenhl 26432355d5 tokio-process: Implement From<StdCommand> for Command (#1513) 2019-08-31 11:45:41 -07:00
Carl Lerche 2f91c85ad8 io: bring back split utility (#1521)
Bring back `split` utility as a free fn instead of a method on
`AsyncRead`. This utility wraps the `stream` in an `Arc` and uses mutual
exclusion to ensure correct access.

Additionally, the specialized `split_mut` fn on TcpStream and UdsStream
is promoted to `split`.
2019-08-30 20:46:07 -07:00
Fenhl 951827229a Add platform-specific methods to Command (#1516) 2019-08-30 18:28:41 -07:00
Geoff Shannon 383bb0a143 test: fix assert format args (#1520) 2019-08-30 14:03:37 -07:00
Benjamin Saunders d2bd6f5002 timer: Rename sleep to delay_for, reexport from tokio (#1518) 2019-08-30 10:23:54 -07:00
Carl Lerche 6a94d2cf4f tls: bump to v0.3.0-alpha.4 (#1515) 2019-08-30 10:20:44 -07:00
kellerkindt 4f99470d46 chore: fix compile error on latest nightly (#1512) 2019-08-30 09:15:05 -07:00
Jarred Nicholls 3d9134d13e executor: shut down idle threads in the blocking pool (#1514) 2019-08-30 08:26:16 -07:00
Sean McArthur 15dc0563b7 prepare v0.2.0-alpha.4 (#1509) 2019-08-29 12:59:10 -07:00
Sean McArthur 4e26258ac3 Re-add temporarily TcpStream::connect_std (#1508) 2019-08-29 11:45:17 -07:00
691 changed files with 45571 additions and 31054 deletions
+1 -2
View File
@@ -13,8 +13,7 @@ task:
setup_script:
- pkg install -y curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
# TODO: switch back to nightly
- sh rustup.sh -y --default-toolchain nightly-2019-08-21
- sh rustup.sh -y --profile minimal --default-toolchain stable
- . $HOME/.cargo/env
- rustup target add i686-unknown-freebsd
- |
+7
View File
@@ -0,0 +1,7 @@
# Code of Conduct
The Tokio project adheres to the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct). This describes the minimum behavior expected from all contributors.
## Enforcement
Instances of violations of the Code of Conduct can be reported by contacting the project team at [[email protected]](mailto:[email protected]).
+3 -3
View File
@@ -12,15 +12,15 @@ use your help.
This guide will help you get started. **Do not let this guide intimidate you**.
It should be considered a map to help you navigate the process.
You may also get help with contributing in the [dev channel][dev], please join
The [dev channel][dev] is available for any concerns not covered in this guide, please join
us!
[dev]: https://gitter.im/tokio-rs/dev
[dev]: https://discord.gg/6yGkFeN
## Conduct
The Tokio project adheres to the [Rust Code of Conduct][coc]. This describes
the _minimum_ behavior expected from all contributors.
the _minimum_ behavior expected from all contributors. Instances of violations of the Code of Conduct can be reported by contacting the project team at [[email protected]](mailto:[email protected]).
[coc]: https://github.com/rust-lang/rust/blob/master/CODE_OF_CONDUCT.md
+7 -9
View File
@@ -2,16 +2,14 @@
members = [
"tokio",
"tokio-buf",
"tokio-codec",
"tokio-executor",
"tokio-fs",
"tokio-io",
"tokio-macros",
"tokio-net",
"tokio-sync",
"tokio-test",
"tokio-timer",
"tokio-tls",
"build-tests",
"tokio-util",
# Internal
"benches",
"examples",
"tests-build",
"tests-integration",
]
+37 -58
View File
@@ -1,7 +1,5 @@
# Tokio
_NOTE_: Tokio's [`master`](https://github.com/tokio-rs/tokio) branch is currently in the process of moving to [`std::future::Future`](https://doc.rust-lang.org/std/future/trait.Future.html), for `v0.1.x` based tokio releases please check out the [`v0.1.x`](https://github.com/tokio-rs/tokio/tree/v0.1.x) branch.
A runtime for writing reliable, asynchronous, and slim applications with
the Rust programming language. It is:
@@ -17,7 +15,7 @@ the Rust programming language. It is:
[![Crates.io][crates-badge]][crates-url]
[![MIT licensed][mit-badge]][mit-url]
[![Build Status][azure-badge]][azure-url]
[![Gitter chat][gitter-badge]][gitter-url]
[![Discord chat][discord-badge]][discord-url]
[crates-badge]: https://img.shields.io/crates/v/tokio.svg
[crates-url]: https://crates.io/crates/tokio
@@ -25,13 +23,14 @@ the Rust programming language. It is:
[mit-url]: LICENSE
[azure-badge]: https://dev.azure.com/tokio-rs/Tokio/_apis/build/status/tokio-rs.tokio?branchName=master
[azure-url]: https://dev.azure.com/tokio-rs/Tokio/_build/latest?definitionId=1&branchName=master
[gitter-badge]: https://img.shields.io/gitter/room/tokio-rs/tokio.svg
[gitter-url]: https://gitter.im/tokio-rs/tokio
[discord-badge]: https://img.shields.io/discord/500028886025895936.svg?logo=discord&style=flat-square
[discord-url]: https://discord.gg/tokio
[Website](https://tokio.rs) |
[Guides](https://tokio.rs/docs/) |
[API Docs](https://docs.rs/tokio/0.2.0-alpha.2/tokio) |
[Chat](https://gitter.im/tokio-rs/tokio)
[Guides](https://tokio.rs/docs/overview/) |
[API Docs](https://docs.rs/tokio/latest/tokio) |
[Roadmap](https://github.com/tokio-rs/tokio/blob/master/ROADMAP.md) |
[Chat](https://discord.gg/tokio)
## Overview
@@ -47,21 +46,20 @@ level, it provides a few major components:
These components provide the runtime components necessary for building
an asynchronous application.
[net]: https://docs.rs/tokio/0.2.0-alpha.2/tokio/net/index.html
[scheduler]: https://docs.rs/tokio/0.2.0-alpha.2/tokio/runtime/index.html
[net]: https://docs.rs/tokio/latest/tokio/net/index.html
[scheduler]: https://docs.rs/tokio/latest/tokio/runtime/index.html
## Example
A basic TCP echo server with Tokio:
```rust
```rust,no_run
use tokio::net::TcpListener;
use tokio::prelude::*;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "127.0.0.1:8080".parse()?;
let mut listener = TcpListener::bind(&addr).unwrap();
let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
@@ -76,14 +74,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(n) if n == 0 => return,
Ok(n) => n,
Err(e) => {
println!("failed to read from socket; err = {:?}", e);
eprintln!("failed to read from socket; err = {:?}", e);
return;
}
};
// Write the data back
if let Err(e) = socket.write_all(&buf[0..n]).await {
println!("failed to write to socket; err = {:?}", e);
eprintln!("failed to write to socket; err = {:?}", e);
return;
}
}
@@ -92,22 +90,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
```
More examples can be found [here](tokio/examples). Note that the `master` branch
is currently being updated to use `async` / `await`. The examples are
not fully ported. Examples for stable Tokio can be found
[here](https://github.com/tokio-rs/tokio/tree/v0.1.x/tokio/examples).
More examples can be found [here](examples).
## Getting Help
First, see if the answer to your question can be found in the [Guides] or the
[API documentation]. If the answer is not there, there is an active community in
the [Tokio Gitter channel][chat]. We would be happy to try to answer your
question. Last, if that doesn't work, try opening an [issue] with the question.
the [Tokio Discord server][chat]. We would be happy to try to answer your
question. Last, if that doesn't work, try opening an [issue] with the question.
[Guides]: https://tokio.rs/docs/
[API documentation]: https://docs.rs/tokio/0.2.0-alpha.2/tokio
[chat]: https://gitter.im/tokio-rs/tokio
[API documentation]: https://docs.rs/tokio/latest/tokio
[chat]: https://discord.gg/tokio
[issue]: https://github.com/tokio-rs/tokio/issues/new
## Contributing
@@ -116,54 +110,39 @@ question. Last, if that doesn't work, try opening an [issue] with the question.
you! We have a [contributing guide][guide] to help you get involved in the Tokio
project.
[guide]: CONTRIBUTING.md
## Project layout
The `tokio` crate, found at the root, is primarily intended for use by
application developers. Library authors should depend on the sub crates, which
have greater guarantees of stability.
The crates included as part of Tokio are:
* [`tokio-executor`]: Task executors and related utilities. Includes a
single-threaded executor and a multi-threaded, work-stealing, executor.
* [`tokio-fs`]: Filesystem (and standard in / out) APIs.
* [`tokio-codec`]: Utilities for encoding and decoding protocol frames.
* [`tokio-io`]: Asynchronous I/O related traits and utilities.
* [`tokio-macros`]: Macros for usage with Tokio.
* [`tokio-net`]: Event loop that drives I/O resources as well as TCP, UDP, and
unix domain socket apis.
* [ `tokio-timer`]: Time related APIs.
[`tokio-codec`]: tokio-codec
[`tokio-current-thread`]: tokio-current-thread
[`tokio-executor`]: tokio-executor
[`tokio-fs`]: tokio-fs
[`tokio-io`]: tokio-io
[`tokio-macros`]: tokio-macros
[`tokio-net`]: tokio-net
[`tokio-timer`]: tokio-timer
[guide]: https://github.com/tokio-rs/tokio/blob/master/CONTRIBUTING.md
## Related Projects
In addition to the crates in this repository, the Tokio project also maintains
several other libraries, including:
* [`hyper`]: A fast and correct HTTP/1.1 and HTTP/2 implementation for Rust.
* [`tonic`]: A gRPC over HTTP/2 implementation focused on high performance, interoperability, and flexibility.
* [`warp`]: A super-easy, composable, web server framework for warp speeds.
* [`tower`]: A library of modular and reusable components for building robust networking clients and servers.
* [`tracing`] (formerly `tokio-trace`): A framework for application-level
tracing and async-aware diagnostics.
* [`rdbc`]: A Rust database connectivity library for MySQL, Postgres and SQLite.
* [`mio`]: A low-level, cross-platform abstraction over OS I/O APIs that powers
`tokio`.
* [`bytes`]: Utilities for working with bytes, including efficient byte buffers.
* [`loom`]: A testing tool for concurrent Rust code
[`warp`]: https://github.com/seanmonstar/warp
[`hyper`]: https://github.com/hyperium/hyper
[`tonic`]: https://github.com/hyperium/tonic
[`tower`]: https://github.com/tower-rs/tower
[`loom`]: https://github.com/tokio-rs/loom
[`rdbc`]: https://github.com/tokio-rs/rdbc
[`tracing`]: https://github.com/tokio-rs/tracing
[`mio`]: https://github.com/tokio-rs/mio
[`bytes`]: https://github.com/tokio-rs/bytes
+67
View File
@@ -0,0 +1,67 @@
# Tokio Roadmap
## A Roadmap to 1.0
The question of "why not 1.0?" has come up a few times. After all, Tokio 0.1 has
been stable for three years. The short answer: because it isn't time. There is
nobody who would rather ship a Tokio 1.0 than us. It also isn't something to rush.
After all, `async / await` only landed in the stable Rust channel weeks ago.
There has been no significant production validation yet, except maybe fuchsia
and that seems like a fairly specialized use case. This release of Tokio
includes significant new code and new strategies with feature flags. Also, there
are still big open questions, such as the [proposed changes][pr-1744] to
`AsyncRead` and `AsyncWrite`.
Tokio 1.0 will be released as soon as the APIs are proven to handle real-world
production cases.
### Tokio 1.0 in Q3 2020 with LTS support
The Tokio 1.0 release will be **no later** than Q3 2020. It will also come with
"long-term support" guarantees:
* A minimum of 5 years of maintenance.
* A minimum of 3 years before a hypothetical 2.0 release.
When Tokio 1.0 is released in Q3 2020, on-going support, security fixes, and
critical bug fixes are guaranteed until **at least** Q3 2025. Tokio 2.0 will not
be released until **at least** Q3 2023 (though, ideally there will never be a
Tokio 2.0 release).
### How to get there
While Tokio 0.1 probably should have been a 1.0, Tokio 0.2 will be a **true**
0.2 release. There will be breaking change releases every 2 ~ 3 months until 1.0.
These changes will be **much** smaller than going from 0.1 -> 0.2. It is
expected that the 1.0 release will look a lot like 0.2.
### What is expected to change
The biggest change will be the `AsyncRead` and `AsyncWrite` traits. Based on
experience gained over the past 3 years, there are a couple of issues to
address:
* Be able to **safely** use uninitialized memory as a read buffer.
* Practical read vectored and write vectored APIs.
There are a few strategies to solve these problems. These strategies need to be
investigated and the solution validated. You can see [this comment][pr-1744-comment] for a
detailed statement of the problem.
The other major change, which has been in the works for a while, is updating
Mio. Mio 0.6 was first released almost 4 years ago and has not had a breaking
change since. Mio 0.7 has been in the works for a while. It includes a full
rewrite of the windows support as well as a refined API. More will be written
about this shortly.
Finally, now that the API is starting to stabilize, effort will be put into
documentation. Tokio 0.2 is being released before updating the website and many
of the old content will no longer be relevant. In the coming weeks, expect to
see updates there.
So, we have our work cut out for us. We hope you enjoy this 0.2 release and are
looking forward to your feedback and help.
[pr-1744]: https://github.com/tokio-rs/tokio/pull/1744
[pr-1744-comment]: https://github.com/tokio-rs/tokio/pull/1744#issuecomment-553575438
+85 -102
View File
@@ -1,132 +1,115 @@
trigger: ["master", "std-future"]
pr: ["master", "std-future"]
trigger: ["master"]
pr: ["master"]
variables:
nightly: nightly-2019-08-21
RUSTFLAGS: -Dwarnings
nightly: nightly-2020-01-25
jobs:
# Test top level crate
- template: ci/azure-test-stable.yml
parameters:
name: test_tokio
rust: stable
displayName: Test tokio
cross: true
crates:
- tokio
- tests-integration
# Test sub crates
- template: ci/azure-test-stable.yml
parameters:
name: test_linux
displayName: Test sub crates -
rust: stable
crates:
- tokio-macros
- tokio-test
- tokio-tls
- tokio-util
- examples
# Run integration tests
- template: ci/azure-test-integration.yml
parameters:
name: test_integration
displayName: Integration tests
rust: stable
# Run tests from `tests-build`. This requires a different process
- template: ci/azure-test-build.yml
parameters:
name: test_build
displayName: Test build permutations
rust: stable
# Run loom tests
- template: ci/azure-loom.yml
parameters:
name: loom
rust: stable
crates:
- tokio
# Try cross compiling
- template: ci/azure-cross-compile.yml
parameters:
name: cross
rust: stable
# Check each feature works properly
- template: ci/azure-check-features.yml
parameters:
rust: $(nightly)
name: check_features
# This represents the minimum Rust version supported by
# Tokio. Updating this should be done in a dedicated PR and
# cannot be greater than two 0.x releases prior to the
# current stable.
#
# Tests are not run as tests may require newer versions of
# rust.
- template: ci/azure-check-minrust.yml
parameters:
name: minrust
rust: 1.39.0
# Check formatting
- template: ci/azure-rustfmt.yml
parameters:
rust: $(nightly)
rust: stable
name: rustfmt
# Apply clippy lints to all crates
- template: ci/azure-clippy.yml
parameters:
rust: $(nightly)
rust: stable
name: clippy
# Test top level crate
- template: ci/azure-test-stable.yml
# Check doc generation
- template: ci/azure-check-docs.yml
parameters:
name: test_tokio
rust: $(nightly)
displayName: Test tokio
cross: true
crates:
tokio:
- codec
- fs
- io
- rt-full
- net
- sync
- tcp
- timer
- udp
- uds
name: docs
# Test crates that are platform specific
- template: ci/azure-test-stable.yml
parameters:
name: test_sub_cross
displayName: Test sub crates (cross) -
cross: true
rust: $(nightly)
crates:
tokio-fs: []
tokio-net:
- process
- signal
- tcp
- udp
- uds
# Test crates that are NOT platform specific
- template: ci/azure-test-stable.yml
parameters:
name: test_linux
displayName: Test sub crates -
rust: $(nightly)
crates:
tokio-buf: []
tokio-codec: []
tokio-executor:
- current-thread
- threadpool
tokio-io:
- util
tokio-sync:
- async-traits
tokio-macros: []
tokio-timer:
- async-traits
tokio-test: []
# Test compilation failure
- template: ci/azure-test-stable.yml
parameters:
name: test_features
displayName: Test feature flags
rust: $(nightly)
crates:
build-tests:
- tokio-executor
- tokio-net
- executor-without-current-thread
- net-no-features
- net-with-tcp
- net-with-udp
- net-with-uds
- tokio-no-features
- tokio-with-net
# # Try cross compiling
# - template: ci/azure-cross-compile.yml
# parameters:
# name: cross_32bit_linux
# target: i686-unknown-linux-gnu
#
# # This represents the minimum Rust version supported by
# # Tokio. Updating this should be done in a dedicated PR and
# # cannot be greater than two 0.x releases prior to the
# # current stable.
# #
# # Tests are not run as tests may require newer versions of
# # rust.
# - template: ci/azure-check-minrust.yml
# parameters:
# name: minrust
# rust_version: 1.34.0
#
# - template: ci/azure-tsan.yml
# parameters:
# name: tsan
# rust: $(nightly)
# rust: stable
- template: ci/azure-deploy-docs.yml
parameters:
rust: $(nightly)
rust: stable
dependsOn:
- rustfmt
- clippy
- test_tokio
- test_sub_cross
- test_linux
- test_features
# - test_nightly
# - cross_32bit_linux
# - minrust
- test_build
- loom
- cross
- minrust
- check_features
# - tsan
+19
View File
@@ -0,0 +1,19 @@
[package]
name = "benches"
version = "0.0.0"
publish = false
edition = "2018"
[dependencies]
tokio = { version = "0.2.0", path = "../tokio", features = ["full"] }
bencher = "0.1.5"
[[bench]]
name = "spawn"
path = "spawn.rs"
harness = false
[[bench]]
name = "mpsc"
path = "mpsc.rs"
harness = false
+188
View File
@@ -0,0 +1,188 @@
use bencher::{black_box, Bencher};
use tokio::sync::mpsc;
type Medium = [usize; 64];
type Large = [Medium; 64];
fn create_1_medium(b: &mut Bencher) {
b.iter(|| {
black_box(&mpsc::channel::<Medium>(1));
});
}
fn create_100_medium(b: &mut Bencher) {
b.iter(|| {
black_box(&mpsc::channel::<Medium>(100));
});
}
fn create_100_000_medium(b: &mut Bencher) {
b.iter(|| {
black_box(&mpsc::channel::<Medium>(100_000));
});
}
fn send_medium(b: &mut Bencher) {
b.iter(|| {
let (mut tx, mut rx) = mpsc::channel::<Medium>(1000);
let _ = tx.try_send([0; 64]);
rx.try_recv().unwrap();
});
}
fn send_large(b: &mut Bencher) {
b.iter(|| {
let (mut tx, mut rx) = mpsc::channel::<Large>(1000);
let _ = tx.try_send([[0; 64]; 64]);
rx.try_recv().unwrap();
});
}
fn contention_bounded(b: &mut Bencher) {
let mut rt = tokio::runtime::Builder::new()
.core_threads(6)
.threaded_scheduler()
.build()
.unwrap();
b.iter(|| {
rt.block_on(async move {
let (tx, mut rx) = mpsc::channel::<usize>(1_000_000);
for _ in 0..5 {
let mut tx = tx.clone();
tokio::spawn(async move {
for i in 0..1000 {
tx.send(i).await.unwrap();
}
});
}
for _ in 0..1_000 * 5 {
let _ = rx.recv().await;
}
})
});
}
fn contention_bounded_full(b: &mut Bencher) {
let mut rt = tokio::runtime::Builder::new()
.core_threads(6)
.threaded_scheduler()
.build()
.unwrap();
b.iter(|| {
rt.block_on(async move {
let (tx, mut rx) = mpsc::channel::<usize>(100);
for _ in 0..5 {
let mut tx = tx.clone();
tokio::spawn(async move {
for i in 0..1000 {
tx.send(i).await.unwrap();
}
});
}
for _ in 0..1_000 * 5 {
let _ = rx.recv().await;
}
})
});
}
fn contention_unbounded(b: &mut Bencher) {
let mut rt = tokio::runtime::Builder::new()
.core_threads(6)
.threaded_scheduler()
.build()
.unwrap();
b.iter(|| {
rt.block_on(async move {
let (tx, mut rx) = mpsc::unbounded_channel::<usize>();
for _ in 0..5 {
let tx = tx.clone();
tokio::spawn(async move {
for i in 0..1000 {
tx.send(i).unwrap();
}
});
}
for _ in 0..1_000 * 5 {
let _ = rx.recv().await;
}
})
});
}
fn uncontented_bounded(b: &mut Bencher) {
let mut rt = tokio::runtime::Builder::new()
.core_threads(6)
.threaded_scheduler()
.build()
.unwrap();
b.iter(|| {
rt.block_on(async move {
let (mut tx, mut rx) = mpsc::channel::<usize>(1_000_000);
for i in 0..5000 {
tx.send(i).await.unwrap();
}
for _ in 0..5_000 {
let _ = rx.recv().await;
}
})
});
}
fn uncontented_unbounded(b: &mut Bencher) {
let mut rt = tokio::runtime::Builder::new()
.core_threads(6)
.threaded_scheduler()
.build()
.unwrap();
b.iter(|| {
rt.block_on(async move {
let (tx, mut rx) = mpsc::unbounded_channel::<usize>();
for i in 0..5000 {
tx.send(i).unwrap();
}
for _ in 0..5_000 {
let _ = rx.recv().await;
}
})
});
}
bencher::benchmark_group!(
create,
create_1_medium,
create_100_medium,
create_100_000_medium
);
bencher::benchmark_group!(send, send_medium, send_large);
bencher::benchmark_group!(
contention,
contention_bounded,
contention_bounded_full,
contention_unbounded,
uncontented_bounded,
uncontented_unbounded
);
bencher::benchmark_main!(create, send, contention);
+70
View File
@@ -0,0 +1,70 @@
//! Benchmark spawning a task onto the basic and threaded Tokio executors.
//! This essentially measure the time to enqueue a task in the local and remote
//! case.
use bencher::{black_box, Bencher};
async fn work() -> usize {
let val = 1 + 1;
black_box(val)
}
fn basic_scheduler_local_spawn(bench: &mut Bencher) {
let mut runtime = tokio::runtime::Builder::new()
.basic_scheduler()
.build()
.unwrap();
runtime.block_on(async {
bench.iter(|| {
let h = tokio::spawn(work());
black_box(h);
})
});
}
fn threaded_scheduler_local_spawn(bench: &mut Bencher) {
let mut runtime = tokio::runtime::Builder::new()
.threaded_scheduler()
.build()
.unwrap();
runtime.block_on(async {
bench.iter(|| {
let h = tokio::spawn(work());
black_box(h);
})
});
}
fn basic_scheduler_remote_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new()
.basic_scheduler()
.build()
.unwrap();
let handle = runtime.handle();
bench.iter(|| {
let h = handle.spawn(work());
black_box(h);
});
}
fn threaded_scheduler_remote_spawn(bench: &mut Bencher) {
let runtime = tokio::runtime::Builder::new()
.threaded_scheduler()
.build()
.unwrap();
let handle = runtime.handle();
bench.iter(|| {
let h = handle.spawn(work());
black_box(h);
});
}
bencher::benchmark_group!(
spawn,
basic_scheduler_local_spawn,
threaded_scheduler_local_spawn,
basic_scheduler_remote_spawn,
threaded_scheduler_remote_spawn
);
bencher::benchmark_main!(spawn);
-25
View File
@@ -1,25 +0,0 @@
[package]
name = "build-tests"
version = "0.1.0"
authors = ["Tokio Contributors <[email protected]>"]
edition = "2018"
publish = false
[features]
executor-without-current-thread = ["tokio-executor"]
net-no-features = ["tokio-net"]
net-with-tcp = ["tokio-net/tcp"]
net-with-udp = ["tokio-net/udp"]
net-with-uds = ["tokio-net/uds"]
tokio-no-features = ["tokio"]
tokio-with-net = ["tokio/net"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio-executor = { path = "../tokio-executor", optional = true }
tokio-net = { path = "../tokio-net", optional = true }
tokio = { path = "../tokio", optional = true, default-features = false }
[dev-dependencies]
trybuild = "1.0"
-8
View File
@@ -1,8 +0,0 @@
#[cfg(feature = "tokio-executor")]
pub use tokio_executor;
#[cfg(feature = "tokio-net")]
pub use tokio_net;
#[cfg(feature = "tokio")]
pub use tokio;
@@ -1,3 +0,0 @@
use build_tests::tokio_executor::current_thread;
fn main() {}
@@ -1,7 +0,0 @@
error[E0432]: unresolved import `build_tests::tokio_executor::current_thread`
--> $DIR/executor_without_current_thread.rs:1:5
|
1 | use build_tests::tokio_executor::current_thread;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `current_thread` in `tokio_executor`
For more information about this error, try `rustc --explain E0432`.
@@ -1,4 +0,0 @@
use build_tests::tokio_net::tcp;
fn main() {}
@@ -1,7 +0,0 @@
error[E0432]: unresolved import `build_tests::tokio_net::tcp`
--> $DIR/net_without_tcp_missing_tcp.rs:1:5
|
1 | use build_tests::tokio_net::tcp;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `tcp` in `tokio_net`
For more information about this error, try `rustc --explain E0432`.
@@ -1,4 +0,0 @@
use build_tests::tokio_net::udp;
fn main() {}
@@ -1,7 +0,0 @@
error[E0432]: unresolved import `build_tests::tokio_net::udp`
--> $DIR/net_without_udp_missing_udp.rs:1:5
|
1 | use build_tests::tokio_net::udp;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `udp` in `tokio_net`
For more information about this error, try `rustc --explain E0432`.
@@ -1,4 +0,0 @@
use build_tests::tokio_net::udp;
fn main() {}
@@ -1,7 +0,0 @@
error[E0432]: unresolved import `build_tests::tokio_net::udp`
--> $DIR/net_without_uds_missing_uds.rs:1:5
|
1 | use build_tests::tokio_net::udp;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `udp` in `tokio_net`
For more information about this error, try `rustc --explain E0432`.
@@ -1,3 +0,0 @@
use build_tests::tokio::net;
fn main() {}
@@ -1,7 +0,0 @@
error[E0432]: unresolved import `build_tests::tokio::net`
--> $DIR/tokio_without_net_missing_net.rs:1:5
|
1 | use build_tests::tokio::net;
| ^^^^^^^^^^^^^^^^^^^^^^^ no `net` in `tokio`
For more information about this error, try `rustc --explain E0432`.
-52
View File
@@ -1,52 +0,0 @@
#![allow(unused_imports)]
#[test]
#[cfg(feature = "tokio-net")]
fn net_default() {
use build_tests::tokio_net::driver::{set_default, Handle, Reactor, Registration};
use build_tests::tokio_net::util::PollEvented;
}
#[test]
#[cfg(feature = "net-with-tcp")]
fn net_with_tcp() {
use build_tests::tokio_net::tcp;
}
#[test]
#[cfg(feature = "net-with-udp")]
fn net_with_udp() {
use build_tests::tokio_net::udp;
}
#[test]
#[cfg(feature = "net-with-uds")]
fn net_with_udp() {
use build_tests::tokio_net::uds;
}
#[test]
#[cfg(feature = "tokio-with-net")]
fn tokio_with_net() {
// net is present
use build_tests::tokio::net;
}
#[test]
fn compile_fail() {
let t = trybuild::TestCases::new();
#[cfg(feature = "executor-without-current-thread")]
t.compile_fail("tests/fail/executor_without_current_thread.rs");
#[cfg(feature = "net-no-features")]
{
t.compile_fail("tests/fail/net_without_tcp_missing_tcp.rs");
t.compile_fail("tests/fail/net_without_udp_missing_udp.rs");
t.compile_fail("tests/fail/net_without_uds_missing_uds.rs");
}
#[cfg(feature = "tokio-no-features")]
t.compile_fail("tests/fail/tokio_without_net_missing_net.rs");
drop(t);
}
+15
View File
@@ -0,0 +1,15 @@
jobs:
# Check docs
- job: ${{ parameters.name }}
displayName: Check docs
pool:
vmImage: ubuntu-16.04
steps:
- template: azure-install-rust.yml
parameters:
rust_version: ${{ parameters.rust }}
- script: |
RUSTDOCFLAGS="--cfg docsrs" cargo doc --lib --no-deps --all-features
displayName: Check docs
+32
View File
@@ -0,0 +1,32 @@
jobs:
- job: ${{ parameters.name }}
displayName: Check features
strategy:
matrix:
Linux:
vmImage: ubuntu-16.04
MacOS:
vmImage: macOS-10.13
Windows:
vmImage: vs2017-win2016
pool:
vmImage: $(vmImage)
steps:
- template: azure-install-rust.yml
parameters:
rust_version: ${{ parameters.rust }}
- template: azure-patch-crates.yml
- script: cargo install cargo-hack
displayName: Install cargo-hack
# Check each feature works properly
# * --each-feature
# run for each feature which includes --no-default-features and default features of package
# * -Z avoid-dev-deps
# build without dev-dependencies to avoid https://github.com/rust-lang/cargo/issues/4866
# tracking-issue: https://github.com/rust-lang/cargo/issues/5133
- script: cargo hack check --all --each-feature -Z avoid-dev-deps
displayName: cargo hack check --all --each-feature
+1 -1
View File
@@ -6,7 +6,7 @@ jobs:
steps:
- template: azure-install-rust.yml
parameters:
rust_version: ${{ parameters.rust_version }}
rust_version: ${{ parameters.rust }}
- template: azure-patch-crates.yml
+1 -1
View File
@@ -12,5 +12,5 @@ jobs:
cargo clippy --version
displayName: Install clippy
- script: |
cargo clippy --all --all-features -- -A clippy::mutex-atomic
cargo clippy --all --all-features
displayName: cargo clippy --all
+26 -9
View File
@@ -1,27 +1,44 @@
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
strategy:
matrix:
i686:
vmImage: ubuntu-16.04
target: i686-unknown-linux-gnu
powerpc:
vmImage: ubuntu-16.04
target: powerpc-unknown-linux-gnu
powerpc64:
vmImage: ubuntu-16.04
target: powerpc64-unknown-linux-gnu
mips:
vmImage: ubuntu-16.04
target: mips-unknown-linux-gnu
arm:
vmImage: ubuntu-16.04
target: arm-linux-androideabi
pool:
vmImage: ubuntu-16.04
vmImage: $(vmImage)
steps:
- template: azure-install-rust.yml
parameters:
rust_version: stable
rust_version: ${{ parameters.rust }}
- script: sudo apt-get update
displayName: "apt-get update"
displayName: apt-get update
- script: sudo apt-get install gcc-multilib
displayName: "Install gcc-multilib"
displayName: Install gcc-multilib
- script: rustup target add ${{ parameters.target }}
displayName: "Add target"
- script: cargo install cross
displayName: Install cross
# Always patch
- template: azure-patch-crates.yml
- script: cargo check --all --exclude tokio-tls --target ${{ parameters.target }}
- script: cross check --all --exclude tokio-tls --target $(target)
displayName: Check source
- script: cargo check --tests --all --exclude tokio-tls --target ${{ parameters.target }}
displayName: Check tests
# - script: cross check --tests --all --exclude tokio-tls --target $(target)
# displayName: Check tests
+2 -2
View File
@@ -2,7 +2,7 @@ steps:
# Linux and macOS.
- script: |
set -e
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none
curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain none
export PATH=$PATH:$HOME/.cargo/bin
rustup toolchain install $RUSTUP_TOOLCHAIN
rustup default $RUSTUP_TOOLCHAIN
@@ -15,7 +15,7 @@ steps:
# Windows.
- script: |
curl -sSf -o rustup-init.exe https://win.rustup.rs
rustup-init.exe -y --default-toolchain none
rustup-init.exe -y --profile minimal --default-toolchain none
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
rustup toolchain install %RUSTUP_TOOLCHAIN%
rustup default %RUSTUP_TOOLCHAIN%
+18
View File
@@ -0,0 +1,18 @@
jobs:
- job: ${{ parameters.name }}
displayName: Loom tests
pool:
vmImage: ubuntu-16.04
steps:
- template: azure-install-rust.yml
parameters:
rust_version: ${{ parameters.rust }}
- ${{ each crate in parameters.crates }}:
- script: RUSTFLAGS="--cfg loom" cargo test --lib --release --features "full" -- --test-threads=1 --nocapture
env:
LOOM_MAX_PREEMPTIONS: 1
CI: 'True'
displayName: test ${{ crate }}
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
+2 -1
View File
@@ -13,5 +13,6 @@ jobs:
cargo fmt --version
displayName: Install rustfmt
- script: |
cargo fmt --all -- --check
# Workaround for rust-lang/cargo#7732
rustfmt --check --edition 2018 $(find . -name '*.rs' -print)
displayName: Check formatting
+17
View File
@@ -0,0 +1,17 @@
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
pool:
vmImage: 'Ubuntu 16.04'
steps:
- template: azure-install-rust.yml
parameters:
rust_version: ${{ parameters.rust }}
- script: cargo install cargo-hack
displayName: Install cargo-hack
- script: cargo hack test --each-feature
displayName: cargo hack test --each-feature
workingDirectory: $(Build.SourcesDirectory)/tests-build
+28
View File
@@ -0,0 +1,28 @@
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
strategy:
matrix:
Linux:
vmImage: ubuntu-16.04
MacOS:
vmImage: macOS-10.13
Windows:
vmImage: vs2017-win2016
pool:
vmImage: $(vmImage)
steps:
- template: azure-install-rust.yml
parameters:
rust_version: ${{ parameters.rust }}
- script: cargo install cargo-hack
displayName: Install cargo-hack
# Run with all crate features
- script: cargo hack test --each-feature
env:
CI: 'True'
displayName: cargo hack test --each-feature
workingDirectory: $(Build.SourcesDirectory)/tests-integration
+12 -26
View File
@@ -17,45 +17,31 @@ jobs:
steps:
- template: azure-install-rust.yml
parameters:
# rust_version: stable
rust_version: ${{ parameters.rust }}
- template: azure-is-release.yml
- ${{ each crate in parameters.crates }}:
# Run with default crate features
- script: cargo test
# Run with all crate features
- script: cargo test --all-features
env:
LOOM_MAX_PREEMPTIONS: 2
CI: 'True'
displayName: ${{ crate.key }} - cargo test
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
displayName: ${{ crate }} - cargo test --all-features
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
# Run with each specified feature
- ${{ each feature in crate.value }}:
- script: cargo test --no-default-features --features ${{ feature }}
env:
LOOM_MAX_PREEMPTIONS: 2
CI: 'True'
displayName: ${{ crate.key }} - cargo test --features ${{ feature }}
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
# Check benches
- script: cargo check --all-features --benches
displayName: ${{ crate }} - cargo check --benches
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
- template: azure-patch-crates.yml
- ${{ each crate in parameters.crates }}:
# Run with default crate features
- script: cargo test
# Run with all crate features
- script: cargo test --all-features
env:
LOOM_MAX_PREEMPTIONS: 2
CI: 'True'
displayName: ${{ crate.key }} - cargo test
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
# Run with each specified feature
- ${{ each feature in crate.value }}:
- script: cargo test --no-default-features --features ${{ feature }}
env:
LOOM_MAX_PREEMPTIONS: 2
CI: 'True'
displayName: ${{ crate.key }} - cargo test --features ${{ feature }}
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
displayName: ${{ crate }} - cargo test --all-features
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
-2
View File
@@ -5,8 +5,6 @@ jobs:
matrix:
Timer:
cmd: cargo test -p tokio-timer --test hammer
Threadpool:
cmd: cargo test -p tokio-executor --tests --features threadpool
pool:
vmImage: ubuntu-16.04
steps:
+2 -8
View File
@@ -2,13 +2,7 @@
# repository.
[patch.crates-io]
tokio = { path = "tokio" }
tokio-buf = { path = "tokio-buf" }
tokio-codec = { path = "tokio-codec" }
tokio-executor = { path = "tokio-executor" }
tokio-fs = { path = "tokio-fs" }
tokio-io = { path = "tokio-io" }
tokio-macros = { path = "tokio-macros" }
tokio-net = { path = "tokio-net" }
tokio-sync = { path = "tokio-sync" }
tokio-timer = { path = "tokio-timer" }
tokio-test = { path = "tokio-test" }
tokio-tls = { path = "tokio-tls" }
tokio-util = { path = "tokio-util" }
+61
View File
@@ -0,0 +1,61 @@
[package]
name = "examples"
version = "0.0.0"
publish = false
edition = "2018"
[dev-dependencies]
tokio = { version = "0.2.0", path = "../tokio", features = ["full"] }
tokio-util = { version = "0.2.0", path = "../tokio-util", features = ["full"] }
bytes = "0.5"
futures = "0.3.0"
http = "0.2"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
httparse = "1.0"
time = "0.1"
[[example]]
name = "chat"
path = "chat.rs"
[[example]]
name = "connect"
path = "connect.rs"
[[example]]
name = "echo-udp"
path = "echo-udp.rs"
[[example]]
name = "echo"
path = "echo.rs"
[[example]]
name = "hello_world"
path = "hello_world.rs"
[[example]]
name = "print_each_packet"
path = "print_each_packet.rs"
[[example]]
name = "proxy"
path = "proxy.rs"
[[example]]
name = "tinydb"
path = "tinydb.rs"
[[example]]
name = "udp-client"
path = "udp-client.rs"
[[example]]
name = "udp-codec"
path = "udp-codec.rs"
[[example]]
name = "tinyhttp"
path = "tinyhttp.rs"
+20
View File
@@ -0,0 +1,20 @@
## Examples of how to use Tokio
This directory contains a number of examples showcasing various capabilities of
the `tokio` crate.
All examples can be executed with:
```
cargo run --example $name
```
A good starting point for the examples would be [`hello_world`](hello_world.rs)
and [`echo`](echo.rs). Additionally [the tokio website][tokioweb] contains
additional guides for some of the examples.
If you've got an example you'd like to see here, please feel free to open an
issue. Otherwise if you've got an example you'd like to add, please feel free
to make a PR!
[tokioweb]: https://tokio.rs/docs/overview/
+31 -29
View File
@@ -26,14 +26,20 @@
#![warn(rust_2018_idioms)]
use futures::{Poll, SinkExt, Stream, StreamExt};
use std::{collections::HashMap, env, error::Error, io, net::SocketAddr, pin::Pin, task::Context};
use tokio::{
self,
codec::{Framed, LinesCodec, LinesCodecError},
net::{TcpListener, TcpStream},
sync::{mpsc, Lock},
};
use tokio::net::{TcpListener, TcpStream};
use tokio::stream::{Stream, StreamExt};
use tokio::sync::{mpsc, Mutex};
use tokio_util::codec::{Framed, LinesCodec, LinesCodecError};
use futures::SinkExt;
use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::io;
use std::net::SocketAddr;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
@@ -42,9 +48,11 @@ async fn main() -> Result<(), Box<dyn Error>> {
// The server task will hold a handle to this. For every new client, the
// `state` handle is cloned and passed into the task that processes the
// client connection.
let state = Lock::new(Shared::new());
let state = Arc::new(Mutex::new(Shared::new()));
let addr = env::args().nth(1).unwrap_or("127.0.0.1:6142".to_string());
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:6142".to_string());
// Bind a TCP listener to the socket address.
//
@@ -58,12 +66,12 @@ async fn main() -> Result<(), Box<dyn Error>> {
let (stream, addr) = listener.accept().await?;
// Clone a handle to the `Shared` state for the new connection.
let state = state.clone();
let state = Arc::clone(&state);
// Spawn our handler to be run asynchronously.
tokio::spawn(async move {
if let Err(e) = process(state, stream, addr).await {
println!("an error occured; error = {:?}", e);
println!("an error occurred; error = {:?}", e);
}
});
}
@@ -111,25 +119,19 @@ impl Shared {
/// Send a `LineCodec` encoded message to every peer, except
/// for the sender.
async fn broadcast(
&mut self,
sender: SocketAddr,
message: &str,
) -> Result<(), mpsc::error::UnboundedSendError> {
async fn broadcast(&mut self, sender: SocketAddr, message: &str) {
for peer in self.peers.iter_mut() {
if *peer.0 != sender {
peer.1.send(message.into()).await?;
let _ = peer.1.send(message.into());
}
}
Ok(())
}
}
impl Peer {
/// Create a new instance of `Peer`.
async fn new(
mut state: Lock<Shared>,
state: Arc<Mutex<Shared>>,
lines: Framed<TcpStream, LinesCodec>,
) -> io::Result<Peer> {
// Get the client socket address
@@ -162,18 +164,18 @@ impl Stream for Peer {
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
// First poll the `UnboundedReceiver`.
if let Poll::Ready(Some(v)) = self.rx.poll_next_unpin(cx) {
if let Poll::Ready(Some(v)) = Pin::new(&mut self.rx).poll_next(cx) {
return Poll::Ready(Some(Ok(Message::Received(v))));
}
// Secondly poll the `Framed` stream.
let result: Option<_> = futures::ready!(self.lines.poll_next_unpin(cx));
let result: Option<_> = futures::ready!(Pin::new(&mut self.lines).poll_next(cx));
Poll::Ready(match result {
// We've received a message we should broadcast to others.
Some(Ok(message)) => Some(Ok(Message::Broadcast(message))),
// An error occured.
// An error occurred.
Some(Err(e)) => Some(Err(e)),
// The stream has been exhausted.
@@ -184,7 +186,7 @@ impl Stream for Peer {
/// Process an individual chat client
async fn process(
mut state: Lock<Shared>,
state: Arc<Mutex<Shared>>,
stream: TcpStream,
addr: SocketAddr,
) -> Result<(), Box<dyn Error>> {
@@ -213,7 +215,7 @@ async fn process(
let mut state = state.lock().await;
let msg = format!("{} has joined the chat", username);
println!("{}", msg);
state.broadcast(addr, &msg).await?;
state.broadcast(addr, &msg).await;
}
// Process incoming messages until our stream is exhausted by a disconnect.
@@ -225,7 +227,7 @@ async fn process(
let mut state = state.lock().await;
let msg = format!("{}: {}", username, msg);
state.broadcast(addr, &msg).await?;
state.broadcast(addr, &msg).await;
}
// A message was received from a peer. Send it to the
// current user.
@@ -234,7 +236,7 @@ async fn process(
}
Err(e) => {
println!(
"an error occured while processing messages for {}; error = {:?}",
"an error occurred while processing messages for {}; error = {:?}",
username, e
);
}
@@ -249,7 +251,7 @@ async fn process(
let msg = format!("{} has left the chat", username);
println!("{}", msg);
state.broadcast(addr, &msg).await?;
state.broadcast(addr, &msg).await;
}
Ok(())
+149
View File
@@ -0,0 +1,149 @@
//! An example of hooking up stdin/stdout to either a TCP or UDP stream.
//!
//! This example will connect to a socket address specified in the argument list
//! and then forward all data read on stdin to the server, printing out all data
//! received on stdout. An optional `--udp` argument can be passed to specify
//! that the connection should be made over UDP instead of TCP, translating each
//! line entered on stdin to a UDP packet to be sent to the remote address.
//!
//! Note that this is not currently optimized for performance, especially
//! around buffer management. Rather it's intended to show an example of
//! working with a client.
//!
//! This example can be quite useful when interacting with the other examples in
//! this repository! Many of them recommend running this as a simple "hook up
//! stdin/stdout to a server" to get up and running.
#![warn(rust_2018_idioms)]
use futures::StreamExt;
use tokio::io;
use tokio_util::codec::{BytesCodec, FramedRead, FramedWrite};
use std::env;
use std::error::Error;
use std::net::SocketAddr;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Determine if we're going to run in TCP or UDP mode
let mut args = env::args().skip(1).collect::<Vec<_>>();
let tcp = match args.iter().position(|a| a == "--udp") {
Some(i) => {
args.remove(i);
false
}
None => true,
};
// Parse what address we're going to connect to
let addr = args
.first()
.ok_or("this program requires at least one argument")?;
let addr = addr.parse::<SocketAddr>()?;
let stdin = FramedRead::new(io::stdin(), BytesCodec::new());
let stdin = stdin.map(|i| i.map(|bytes| bytes.freeze()));
let stdout = FramedWrite::new(io::stdout(), BytesCodec::new());
if tcp {
tcp::connect(&addr, stdin, stdout).await?;
} else {
udp::connect(&addr, stdin, stdout).await?;
}
Ok(())
}
mod tcp {
use bytes::Bytes;
use futures::{future, Sink, SinkExt, Stream, StreamExt};
use std::{error::Error, io, net::SocketAddr};
use tokio::net::TcpStream;
use tokio_util::codec::{BytesCodec, FramedRead, FramedWrite};
pub async fn connect(
addr: &SocketAddr,
mut stdin: impl Stream<Item = Result<Bytes, io::Error>> + Unpin,
mut stdout: impl Sink<Bytes, Error = io::Error> + Unpin,
) -> Result<(), Box<dyn Error>> {
let mut stream = TcpStream::connect(addr).await?;
let (r, w) = stream.split();
let mut sink = FramedWrite::new(w, BytesCodec::new());
// filter map Result<BytesMut, Error> stream into just a Bytes stream to match stdout Sink
// on the event of an Error, log the error and end the stream
let mut stream = FramedRead::new(r, BytesCodec::new())
.filter_map(|i| match i {
//BytesMut into Bytes
Ok(i) => future::ready(Some(i.freeze())),
Err(e) => {
println!("failed to read from socket; error={}", e);
future::ready(None)
}
})
.map(Ok);
match future::join(sink.send_all(&mut stdin), stdout.send_all(&mut stream)).await {
(Err(e), _) | (_, Err(e)) => Err(e.into()),
_ => Ok(()),
}
}
}
mod udp {
use bytes::Bytes;
use futures::{future, Sink, SinkExt, Stream, StreamExt};
use std::error::Error;
use std::io;
use std::net::SocketAddr;
use tokio::net::udp::{RecvHalf, SendHalf};
use tokio::net::UdpSocket;
pub async fn connect(
addr: &SocketAddr,
stdin: impl Stream<Item = Result<Bytes, io::Error>> + Unpin,
stdout: impl Sink<Bytes, Error = io::Error> + Unpin,
) -> Result<(), Box<dyn Error>> {
// We'll bind our UDP socket to a local IP/port, but for now we
// basically let the OS pick both of those.
let bind_addr = if addr.ip().is_ipv4() {
"0.0.0.0:0"
} else {
"[::]:0"
};
let socket = UdpSocket::bind(&bind_addr).await?;
socket.connect(addr).await?;
let (mut r, mut w) = socket.split();
future::try_join(send(stdin, &mut w), recv(stdout, &mut r)).await?;
Ok(())
}
async fn send(
mut stdin: impl Stream<Item = Result<Bytes, io::Error>> + Unpin,
writer: &mut SendHalf,
) -> Result<(), io::Error> {
while let Some(item) = stdin.next().await {
let buf = item?;
writer.send(&buf[..]).await?;
}
Ok(())
}
async fn recv(
mut stdout: impl Sink<Bytes, Error = io::Error> + Unpin,
reader: &mut RecvHalf,
) -> Result<(), io::Error> {
loop {
let mut buf = vec![0; 1024];
let n = reader.recv(&mut buf[..]).await?;
if n > 0 {
stdout.send(Bytes::from(buf)).await?;
}
}
}
}
@@ -51,7 +51,9 @@ impl Server {
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:8080".to_string());
let socket = UdpSocket::bind(&addr).await?;
println!("Listening on: {}", socket.local_addr()?);
+3 -1
View File
@@ -33,7 +33,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Allow passing an address to listen on as the first argument of this
// program, but otherwise we'll just set up our TCP listener on
// 127.0.0.1:8080 for connections.
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:8080".to_string());
// Next up we create a TCP listener which will listen for incoming
// connections. This TCP listener is bound to the address we determined
@@ -54,10 +54,9 @@
#![warn(rust_2018_idioms)]
use tokio;
use tokio::codec::{BytesCodec, Decoder};
use tokio::net::TcpListener;
use tokio::prelude::*;
use tokio::stream::StreamExt;
use tokio_util::codec::{BytesCodec, Decoder};
use std::env;
@@ -66,7 +65,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Allow passing an address to listen on as the first argument of this
// program, but otherwise we'll just set up our TCP listener on
// 127.0.0.1:8080 for connections.
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:8080".to_string());
// Next up we create a TCP listener which will listen for incoming
// connections. This TCP listener is bound to the address we determined
+19 -14
View File
@@ -22,24 +22,29 @@
#![warn(rust_2018_idioms)]
use futures::{future::try_join, FutureExt, StreamExt};
use std::{env, error::Error};
use tokio::{
io::AsyncReadExt,
net::{TcpListener, TcpStream},
};
use tokio::io;
use tokio::net::{TcpListener, TcpStream};
use futures::future::try_join;
use futures::FutureExt;
use std::env;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let listen_addr = env::args().nth(1).unwrap_or("127.0.0.1:8081".to_string());
let server_addr = env::args().nth(2).unwrap_or("127.0.0.1:8080".to_string());
let listen_addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:8081".to_string());
let server_addr = env::args()
.nth(2)
.unwrap_or_else(|| "127.0.0.1:8080".to_string());
println!("Listening on: {}", listen_addr);
println!("Proxying to: {}", server_addr);
let mut incoming = TcpListener::bind(listen_addr).await?.incoming();
let mut listener = TcpListener::bind(listen_addr).await?;
while let Some(Ok(inbound)) = incoming.next().await {
while let Ok((inbound, _)) = listener.accept().await {
let transfer = transfer(inbound, server_addr.clone()).map(|r| {
if let Err(e) = r {
println!("Failed to transfer; error={}", e);
@@ -52,14 +57,14 @@ async fn main() -> Result<(), Box<dyn Error>> {
Ok(())
}
async fn transfer(inbound: TcpStream, proxy_addr: String) -> Result<(), Box<dyn Error>> {
let outbound = TcpStream::connect(proxy_addr).await?;
async fn transfer(mut inbound: TcpStream, proxy_addr: String) -> Result<(), Box<dyn Error>> {
let mut outbound = TcpStream::connect(proxy_addr).await?;
let (mut ri, mut wi) = inbound.split();
let (mut ro, mut wo) = outbound.split();
let client_to_server = ri.copy(&mut wo);
let server_to_client = ro.copy(&mut wi);
let client_to_server = io::copy(&mut ri, &mut wo);
let server_to_client = io::copy(&mut ro, &mut wi);
try_join(client_to_server, server_to_client).await?;
+14 -16
View File
@@ -41,17 +41,16 @@
#![warn(rust_2018_idioms)]
use tokio::net::TcpListener;
use tokio::stream::StreamExt;
use tokio_util::codec::{Framed, LinesCodec};
use futures::SinkExt;
use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::sync::{Arc, Mutex};
use tokio;
use tokio::codec::{Framed, LinesCodec};
use tokio::net::TcpListener;
use futures::{SinkExt, StreamExt};
/// The in-memory database shared amongst all clients.
///
/// This database will be shared via `Arc`, so to mutate the internal map we're
@@ -86,7 +85,9 @@ enum Response {
async fn main() -> Result<(), Box<dyn Error>> {
// Parse the address we're going to run this server on
// and set up our TCP listener to accept connections.
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:8080".to_string());
let mut listener = TcpListener::bind(&addr).await?;
println!("Listening on: {}", addr);
@@ -177,15 +178,12 @@ fn handle_request(line: &str, db: &Arc<Database>) -> Response {
impl Request {
fn parse(input: &str) -> Result<Request, String> {
let mut parts = input.splitn(3, " ");
let mut parts = input.splitn(3, ' ');
match parts.next() {
Some("GET") => {
let key = match parts.next() {
Some(key) => key,
None => return Err(format!("GET must be followed by a key")),
};
let key = parts.next().ok_or("GET must be followed by a key")?;
if parts.next().is_some() {
return Err(format!("GET's key must not be followed by anything"));
return Err("GET's key must not be followed by anything".into());
}
Ok(Request::Get {
key: key.to_string(),
@@ -194,11 +192,11 @@ impl Request {
Some("SET") => {
let key = match parts.next() {
Some(key) => key,
None => return Err(format!("SET must be followed by a key")),
None => return Err("SET must be followed by a key".into()),
};
let value = match parts.next() {
Some(value) => value,
None => return Err(format!("SET needs a value")),
None => return Err("SET needs a value".into()),
};
Ok(Request::Set {
key: key.to_string(),
@@ -206,7 +204,7 @@ impl Request {
})
}
Some(cmd) => Err(format!("unknown command: {}", cmd)),
None => Err(format!("empty input")),
None => Err("empty input".into()),
}
}
}
@@ -14,22 +14,25 @@
#![warn(rust_2018_idioms)]
use bytes::BytesMut;
use futures::{SinkExt, StreamExt};
use futures::SinkExt;
use http::{header::HeaderValue, Request, Response, StatusCode};
use serde::Serialize;
#[macro_use]
extern crate serde_derive;
use serde_json;
use std::{env, error::Error, fmt, io};
use tokio::{
codec::{Decoder, Encoder, Framed},
net::{TcpListener, TcpStream},
};
use tokio::net::{TcpListener, TcpStream};
use tokio::stream::StreamExt;
use tokio_util::codec::{Decoder, Encoder, Framed};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Parse the arguments, bind the TCP socket we'll be listening to, spin up
// our worker threads, and start shipping sockets to those worker threads.
let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
let mut incoming = TcpListener::bind(&addr).await?.incoming();
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:8080".to_string());
let mut server = TcpListener::bind(&addr).await?;
let mut incoming = server.incoming();
println!("Listening on: {}", addr);
while let Some(Ok(stream)) = incoming.next().await {
@@ -63,11 +66,11 @@ async fn respond(req: Request<()>) -> Result<Response<String>, Box<dyn Error>> {
let mut response = Response::builder();
let body = match req.uri().path() {
"/plaintext" => {
response.header("Content-Type", "text/plain");
response = response.header("Content-Type", "text/plain");
"Hello, World!".to_string()
}
"/json" => {
response.header("Content-Type", "application/json");
response = response.header("Content-Type", "application/json");
#[derive(Serialize)]
struct Message {
@@ -78,7 +81,7 @@ async fn respond(req: Request<()>) -> Result<Response<String>, Box<dyn Error>> {
})?
}
_ => {
response.status(StatusCode::NOT_FOUND);
response = response.status(StatusCode::NOT_FOUND);
String::new()
}
};
@@ -196,16 +199,19 @@ impl Decoder for Http {
}
let data = src.split_to(amt).freeze();
let mut ret = Request::builder();
ret.method(&data[method.0..method.1]);
ret.uri(data.slice(path.0, path.1));
ret.version(http::Version::HTTP_11);
ret = ret.method(&data[method.0..method.1]);
let s = data.slice(path.0..path.1);
let s = unsafe { String::from_utf8_unchecked(Vec::from(s.as_ref())) };
ret = ret.uri(s);
ret = ret.version(http::Version::HTTP_11);
for header in headers.iter() {
let (k, v) = match *header {
Some((ref k, ref v)) => (k, v),
None => break,
};
let value = unsafe { HeaderValue::from_shared_unchecked(data.slice(v.0, v.1)) };
ret.header(&data[k.0..k.1], value);
let value = HeaderValue::from_bytes(data.slice(v.0..v.1).as_ref())
.map_err(|_| io::Error::new(io::ErrorKind::Other, "header decode error"))?;
ret = ret.header(&data[k.0..k.1], value);
}
let req = ret
@@ -44,7 +44,7 @@ fn get_stdin_data() -> Result<Vec<u8>, Box<dyn std::error::Error>> {
async fn main() -> Result<(), Box<dyn Error>> {
let remote_addr: SocketAddr = env::args()
.nth(1)
.unwrap_or("127.0.0.1:8080".into())
.unwrap_or_else(|| "127.0.0.1:8080".into())
.parse()?;
// We use port 0 to let the operating system allocate an available port for us.
@@ -6,27 +6,26 @@
//! new message with a new destination. Overall, we then use this to construct a
//! "ping pong" pair where two sockets are sending messages back and forth.
#![cfg(feature = "rt-full")]
#![warn(rust_2018_idioms)]
use tokio::net::UdpSocket;
use tokio::stream::StreamExt;
use tokio::{io, time};
use tokio_util::codec::BytesCodec;
use tokio_util::udp::UdpFramed;
use bytes::Bytes;
use futures::{FutureExt, SinkExt};
use std::env;
use std::error::Error;
use std::net::SocketAddr;
use std::time::Duration;
use bytes::Bytes;
use futures::{FutureExt, SinkExt, StreamExt};
use tokio::codec::BytesCodec;
use tokio::future::FutureExt as TokioFutureExt;
use tokio::io;
use tokio::net::{UdpFramed, UdpSocket};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let _ = env_logger::init();
let addr = env::args().nth(1).unwrap_or("127.0.0.1:0".to_string());
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:0".to_string());
// Bind both our sockets and then figure out what ports we got.
let a = UdpSocket::bind(&addr).await?;
@@ -47,7 +46,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Run both futures simultaneously of `a` and `b` sending messages back and forth.
match futures::future::try_join(a, b).await {
Err(e) => println!("an error occured; error = {:?}", e),
Err(e) => println!("an error occurred; error = {:?}", e),
_ => println!("done!"),
}
@@ -71,7 +70,7 @@ async fn ping(socket: &mut UdpFramed<BytesCodec>, b_addr: SocketAddr) -> Result<
async fn pong(socket: &mut UdpFramed<BytesCodec>) -> Result<(), io::Error> {
let timeout = Duration::from_millis(200);
while let Ok(Some(Ok((bytes, addr)))) = socket.next().timeout(timeout).await {
while let Ok(Some(Ok((bytes, addr)))) = time::timeout(timeout, socket.next()).await {
println!("[b] recv: {}", String::from_utf8_lossy(&bytes));
socket.send((Bytes::from(&b"PONG"[..]), addr)).await?;
-1
View File
@@ -1 +0,0 @@
nightly-2019-08-21
+15
View File
@@ -0,0 +1,15 @@
[package]
name = "tests-build"
version = "0.1.0"
authors = ["Tokio Contributors <[email protected]>"]
edition = "2018"
publish = false
[features]
full = ["tokio/full"]
[dependencies]
tokio = { path = "../tokio", optional = true }
[dev-dependencies]
trybuild = "1.0"
+2
View File
@@ -0,0 +1,2 @@
#[cfg(feature = "tokio")]
pub use tokio;
@@ -0,0 +1,25 @@
use tests_build::tokio;
#[tokio::main]
fn main_is_not_async() {}
#[tokio::main(foo)]
async fn main_attr_has_unknown_args() {}
#[tokio::main(threadpool::bar)]
async fn main_attr_has_path_args() {}
#[tokio::test]
fn test_is_not_async() {}
#[tokio::test]
async fn test_fn_has_args(_x: u8) {}
#[tokio::test(foo)]
async fn test_attr_has_args() {}
#[tokio::test]
#[test]
async fn test_has_second_test_attr() {}
fn main() {}
@@ -0,0 +1,41 @@
error: the async keyword is missing from the function declaration
--> $DIR/macros_invalid_input.rs:4:1
|
4 | fn main_is_not_async() {}
| ^^
error: Unknown attribute foo is specified; expected `basic_scheduler` or `threaded_scheduler`
--> $DIR/macros_invalid_input.rs:6:15
|
6 | #[tokio::main(foo)]
| ^^^
error: Must have specified ident
--> $DIR/macros_invalid_input.rs:9:15
|
9 | #[tokio::main(threadpool::bar)]
| ^^^^^^^^^^^^^^^
error: the async keyword is missing from the function declaration
--> $DIR/macros_invalid_input.rs:13:1
|
13 | fn test_is_not_async() {}
| ^^
error: the test function cannot accept arguments
--> $DIR/macros_invalid_input.rs:16:27
|
16 | async fn test_fn_has_args(_x: u8) {}
| ^^^^^^
error: Unknown attribute foo is specified; expected `basic_scheduler` or `threaded_scheduler`
--> $DIR/macros_invalid_input.rs:18:15
|
18 | #[tokio::test(foo)]
| ^^^
error: second test attribute is supplied
--> $DIR/macros_invalid_input.rs:22:1
|
22 | #[test]
| ^^^^^^^
+9
View File
@@ -0,0 +1,9 @@
#[test]
fn compile_fail() {
let t = trybuild::TestCases::new();
#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_invalid_input.rs");
drop(t);
}
+27
View File
@@ -0,0 +1,27 @@
[package]
name = "tests-integration"
version = "0.1.0"
authors = ["Tokio Contributors <[email protected]>"]
edition = "2018"
publish = false
[features]
full = [
"macros",
"rt-core",
"rt-threaded",
"tokio/full",
"tokio-test"
]
macros = ["tokio/macros"]
rt-core = ["tokio/rt-core"]
rt-threaded = ["rt-core", "tokio/rt-threaded"]
[dependencies]
tokio = { path = "../tokio" }
tokio-test = { path = "../tokio-test", optional = true }
doc-comment = "0.3.1"
[dev-dependencies]
futures = { version = "0.3.0", features = ["async-await"] }
+1
View File
@@ -0,0 +1 @@
Tests that require additional components than just the `tokio` crate.
+2
View File
@@ -0,0 +1,2 @@
#[cfg(feature = "full")]
doc_comment::doc_comment!(include_str!("../../README.md"));
+31
View File
@@ -0,0 +1,31 @@
#![cfg(feature = "macros")]
#[tokio::main]
async fn basic_main() -> usize {
1
}
#[tokio::main]
async fn generic_fun<T: Default>() -> T {
T::default()
}
#[cfg(feature = "rt-core")]
mod spawn {
#[tokio::main]
async fn spawning() -> usize {
let join = tokio::spawn(async { 1 });
join.await.unwrap()
}
#[test]
fn main_with_spawn() {
assert_eq!(1, spawning());
}
}
#[test]
fn shell() {
assert_eq!(1, basic_main());
assert_eq!(bool::default(), generic_fun::<bool>())
}
+12
View File
@@ -0,0 +1,12 @@
use futures::executor::block_on;
async fn my_async_fn() {}
#[test]
fn pin() {
block_on(async {
let future = my_async_fn();
tokio::pin!(future);
(&mut future).await
});
}
+33
View File
@@ -0,0 +1,33 @@
#![cfg(feature = "macros")]
use futures::channel::oneshot;
use futures::executor::block_on;
use std::thread;
#[test]
fn join_with_select() {
block_on(async {
let (tx1, mut rx1) = oneshot::channel::<i32>();
let (tx2, mut rx2) = oneshot::channel::<i32>();
thread::spawn(move || {
tx1.send(123).unwrap();
tx2.send(456).unwrap();
});
let mut a = None;
let mut b = None;
while a.is_none() || b.is_none() {
tokio::select! {
v1 = (&mut rx1), if a.is_none() => a = Some(v1.unwrap()),
v2 = (&mut rx2), if b.is_none() => b = Some(v2.unwrap()),
}
}
let (a, b) = (a.unwrap(), b.unwrap());
assert_eq!(a, 123);
assert_eq!(b, 456);
});
}
@@ -1,23 +1,15 @@
#![cfg(feature = "process")]
#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
#[macro_use]
extern crate tracing;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::process::{Child, Command};
use tokio_test::assert_ok;
use futures::future::{self, FutureExt};
use std::env;
use std::io;
use std::process::{ExitStatus, Stdio};
use futures_util::future;
use futures_util::future::FutureExt;
use futures_util::stream::StreamExt;
use tokio::codec::{FramedRead, LinesCodec};
use tokio::io::AsyncWriteExt;
use tokio_net::process::{Child, Command};
mod support;
use support::*;
fn cat() -> Command {
let mut me = env::current_exe().unwrap();
me.pop();
@@ -34,15 +26,12 @@ fn cat() -> Command {
}
async fn feed_cat(mut cat: Child, n: usize) -> io::Result<ExitStatus> {
let mut stdin = cat.stdin().take().unwrap();
let stdout = cat.stdout().take().unwrap();
let mut stdin = cat.stdin.take().unwrap();
let stdout = cat.stdout.take().unwrap();
// Produce n lines on the child's stdout.
let write = async {
debug!("starting to feed");
for i in 0..n {
debug!("sending line {} to child", i);
let bytes = format!("line {}\n", i).into_bytes();
stdin.write_all(&bytes).await.unwrap();
}
@@ -51,28 +40,21 @@ async fn feed_cat(mut cat: Child, n: usize) -> io::Result<ExitStatus> {
};
let read = async {
let mut reader = FramedRead::new(stdout, LinesCodec::new());
let mut reader = BufReader::new(stdout).lines();
let mut num_lines = 0;
// Try to read `n + 1` lines, ensuring the last one is empty
// (i.e. EOF is reached after `n` lines.
loop {
debug!("starting read from child");
let data = reader
.next()
.next_line()
.await
.unwrap_or_else(|| Ok(String::new()))
.unwrap_or_else(|_| Some(String::new()))
.expect("failed to read line");
let num_read = data.len();
let done = num_lines >= n;
debug!(
"read line {} from child ({} bytes, done: {})",
num_lines, num_read, done
);
match (done, num_read) {
(false, 0) => panic!("broken pipe"),
(true, n) if n != 0 => panic!("extraneous data"),
@@ -109,14 +91,14 @@ async fn feed_cat(mut cat: Child, n: usize) -> io::Result<ExitStatus> {
#[tokio::test]
async fn feed_a_lot() {
let child = cat().spawn().unwrap();
let status = with_timeout(feed_cat(child, 10000)).await.unwrap();
let status = feed_cat(child, 10000).await.unwrap();
assert_eq!(status.code(), Some(0));
}
#[tokio::test]
async fn wait_with_output_captures() {
let mut child = cat().spawn().unwrap();
let mut stdin = child.stdin().take().unwrap();
let mut stdin = child.stdin.take().unwrap();
let write_bytes = b"1234";
@@ -127,7 +109,7 @@ async fn wait_with_output_captures() {
out.await
};
let output = with_timeout(future).await.unwrap();
let output = future.await.unwrap();
assert!(output.status.success());
assert_eq!(output.stdout, write_bytes);
@@ -139,9 +121,7 @@ async fn status_closes_any_pipes() {
// Cat will open a pipe between the parent and child.
// If `status_async` doesn't ensure the handles are closed,
// we would end up blocking forever (and time out).
let child = cat().status().expect("failed to spawn child");
let child = cat().status();
with_timeout(child)
.await
.expect("time out exceeded! did we get stuck waiting on the child?");
assert_ok!(child.await);
}
-19
View File
@@ -1,19 +0,0 @@
# 0.2.0-alpha.1 (August 8, 2019)
### Changed
- Switch to `async`, `await`, and `std::future`.
# 0.1.1 (April 22, 2019)
### Added
- Utilities for creating a `BufStream` from iterators and streams (#1011).
- Add `BufStream::into_stream` (#1048).
- Implement `FromBufStream` for `Bytes` (#1009).
- Implement `Error` for `CollectVecError` (#1010).
### Fixed
- Implement `size_hint` for string types (#1012).
# 0.1.0 (February 23, 2019)
* Initial release
-34
View File
@@ -1,34 +0,0 @@
[package]
name = "tokio-buf"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "v0.2.x" git tag.
version = "0.2.0-alpha.1"
edition = "2018"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-buf/0.2.0-alpha.1/tokio_buf"
description = """
Asynchronous stream of byte buffers
"""
categories = ["asynchronous"]
[dependencies]
bytes = "0.4.10"
either = { version = "1.5", optional = true}
[features]
# default = ["util"]
# util = ["bytes/either", "either"]
[dev-dependencies]
tokio-mock-task = "0.1.1"
[package.metadata.docs.rs]
all-features = true
-13
View File
@@ -1,13 +0,0 @@
# tokio-buf
Asynchronous stream of byte buffers
## License
This project is licensed under the [MIT license](LICENSE).
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Tokio by you, shall be licensed as MIT, without any additional
terms or conditions.
-98
View File
@@ -1,98 +0,0 @@
#![doc(html_root_url = "https://docs.rs/tokio-buf/0.2.0-alpha.1")]
#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unreachable_pub
)]
#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]
//! Asynchronous stream of bytes.
//!
//! This crate contains the `BufStream` trait and a number of combinators for
//! this trait. The trait is similar to `Stream` in the `futures` library, but
//! instead of yielding arbitrary values, it only yields types that implement
//! `Buf` (i.e, byte collections).
// mod never;
mod size_hint;
// mod str;
// mod u8;
// #[cfg(feature = "util")]
// pub mod util;
pub use self::size_hint::SizeHint;
// #[doc(inline)]
// #[cfg(feature = "util")]
// pub use crate::util::BufStreamExt;
use bytes::Buf;
use std::task::{Context, Poll};
/// An asynchronous stream of bytes.
///
/// `BufStream` asynchronously yields values implementing `Buf`, i.e. byte
/// buffers.
pub trait BufStream {
/// Values yielded by the `BufStream`.
///
/// Each item is a sequence of bytes representing a chunk of the total
/// `ByteStream`.
type Item: Buf;
/// The error type this `BufStream` might generate.
type Error;
/// Attempt to pull out the next buffer of this stream, registering the
/// current task for wakeup if the value is not yet available, and returning
/// `None` if the stream is exhausted.
///
/// # Return value
///
/// There are several possible return values, each indicating a distinct
/// stream state:
///
/// - `Poll::Pending` means that this stream's next value is not ready yet.
/// Implementations will ensure that the current task will be notified
/// when the next value may be ready.
///
/// - `Poll::Ready(Some(Ok(buf)))` means that the stream has successfully
/// produced a value, `buf`, and may produce further values on subsequent
/// `poll_buf` calls.
///
/// - `Poll::Ready(None)` means that the stream has terminated, and
/// `poll_buf` should not be invoked again.
///
/// # Panics
///
/// Once a stream is finished, i.e. `Poll::Ready(None)` has been returned,
/// further calls to `poll_buf` may result in a panic or other "bad
/// behavior".
fn poll_buf(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Self::Item, Self::Error>>>;
/// Returns the bounds on the remaining length of the stream.
///
/// The size hint allows the caller to perform certain optimizations that
/// are dependent on the byte stream size. For example, `collect` uses the
/// size hint to pre-allocate enough capacity to store the entirety of the
/// data received from the byte stream.
///
/// When `SizeHint::upper()` returns `Some` with a value equal to
/// `SizeHint::lower()`, this represents the exact number of bytes that will
/// be yielded by the `BufStream`.
///
/// # Implementation notes
///
/// While not enforced, implementations are expected to respect the values
/// returned from `SizeHint`. Any deviation is considered an implementation
/// bug. Consumers may rely on correctness in order to use the value as part
/// of protocol impelmentations. For example, an HTTP library may use the
/// size hint to set the `content-length` header.
///
/// However, `size_hint` must not be trusted to omit bounds checks in unsafe
/// code. An incorrect implementation of `size_hint()` must not lead to
/// memory safety violations.
fn size_hint(&self) -> SizeHint {
SizeHint::default()
}
}
-18
View File
@@ -1,18 +0,0 @@
use std::{error, fmt};
/// An error that can never occur
pub enum Never {}
impl fmt::Debug for Never {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {}
}
}
impl fmt::Display for Never {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {}
}
}
impl error::Error for Never {}
-56
View File
@@ -1,56 +0,0 @@
use std::u64;
/// A `BufStream` size hint
///
/// The default implementation returns:
///
/// * 0 for `available`
/// * 0 for `lower`
/// * `None` for `upper`.
#[derive(Debug, Default, Clone)]
pub struct SizeHint {
lower: u64,
upper: Option<u64>,
}
impl SizeHint {
/// Returns a new `SizeHint` with default values
pub fn new() -> SizeHint {
SizeHint::default()
}
/// Returns the lower bound of data that the `BufStream` will yield before
/// completing.
pub fn lower(&self) -> u64 {
self.lower
}
/// Set the value of the `lower` hint.
///
/// # Panics
///
/// The function panics if `value` is greater than `upper`.
pub fn set_lower(&mut self, value: u64) {
assert!(value <= self.upper.unwrap_or(u64::MAX));
self.lower = value;
}
/// Returns the upper bound of data the `BufStream` will yield before
/// completing, or `None` if the value is unknown.
pub fn upper(&self) -> Option<u64> {
self.upper
}
/// Set the value of the `upper` hint value.
///
/// # Panics
///
/// This function panics if `value` is less than `lower`.
pub fn set_upper(&mut self, value: u64) {
// There is no need to check `available` as that is guaranteed to be
// less than or equal to `lower`.
assert!(value >= self.lower, "`value` is less than than `lower`");
self.upper = Some(value);
}
}
-55
View File
@@ -1,55 +0,0 @@
use crate::never::Never;
use crate::BufStream;
use crate::SizeHint;
use futures::Poll;
use std::io;
use std::mem;
impl BufStream for String {
type Item = io::Cursor<Vec<u8>>;
type Error = Never;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if self.is_empty() {
return Ok(None.into());
}
let bytes = mem::replace(self, Default::default()).into_bytes();
let buf = io::Cursor::new(bytes);
Ok(Some(buf).into())
}
fn size_hint(&self) -> SizeHint {
size_hint(&self[..])
}
}
impl BufStream for &'static str {
type Item = io::Cursor<&'static [u8]>;
type Error = Never;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if self.is_empty() {
return Ok(None.into());
}
let bytes = mem::replace(self, Default::default()).as_bytes();
let buf = io::Cursor::new(bytes);
Ok(Some(buf).into())
}
fn size_hint(&self) -> SizeHint {
size_hint(&self[..])
}
}
fn size_hint(s: &str) -> SizeHint {
let mut hint = SizeHint::new();
hint.set_lower(s.len() as u64);
hint.set_upper(s.len() as u64);
hint
}
-66
View File
@@ -1,66 +0,0 @@
use crate::never::Never;
use crate::BufStream;
use bytes::{Bytes, BytesMut};
use futures::Poll;
use std::io;
impl BufStream for Vec<u8> {
type Item = io::Cursor<Vec<u8>>;
type Error = Never;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if self.is_empty() {
return Ok(None.into());
}
poll_bytes(self)
}
}
impl BufStream for &'static [u8] {
type Item = io::Cursor<&'static [u8]>;
type Error = Never;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if self.is_empty() {
return Ok(None.into());
}
poll_bytes(self)
}
}
impl BufStream for Bytes {
type Item = io::Cursor<Bytes>;
type Error = Never;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if self.is_empty() {
return Ok(None.into());
}
poll_bytes(self)
}
}
impl BufStream for BytesMut {
type Item = io::Cursor<BytesMut>;
type Error = Never;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if self.is_empty() {
return Ok(None.into());
}
poll_bytes(self)
}
}
fn poll_bytes<T: Default>(buf: &mut T) -> Poll<Option<io::Cursor<T>>, Never> {
use std::mem;
let bytes = mem::replace(buf, Default::default());
let buf = io::Cursor::new(bytes);
Ok(Some(buf).into())
}
-46
View File
@@ -1,46 +0,0 @@
use crate::BufStream;
use either::Either;
use futures::{try_ready, Poll};
/// A buf stream that sequences two buf streams together.
///
/// `Chain` values are produced by the `chain` function on `BufStream`.
#[derive(Debug)]
pub struct Chain<T, U> {
left: Option<T>,
right: U,
}
impl<T, U> Chain<T, U> {
pub(crate) fn new(left: T, right: U) -> Chain<T, U> {
Chain {
left: Some(left),
right,
}
}
}
impl<T, U> BufStream for Chain<T, U>
where
T: BufStream,
U: BufStream<Error = T::Error>,
{
type Item = Either<T::Item, U::Item>;
type Error = T::Error;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if let Some(ref mut stream) = self.left {
let res = try_ready!(stream.poll_buf());
if res.is_some() {
return Ok(res.map(Either::Left).into());
}
}
self.left = None;
let res = try_ready!(self.right.poll_buf());
Ok(res.map(Either::Right).into())
}
}
-101
View File
@@ -1,101 +0,0 @@
use super::FromBufStream;
use crate::BufStream;
use futures::{try_ready, Future, Poll};
/// Consumes a buf stream, collecting the data into a single byte container.
///
/// `Collect` values are produced by `BufStream::collect`.
#[derive(Debug)]
pub struct Collect<T, U>
where
T: BufStream,
U: FromBufStream<T::Item>,
{
stream: T,
builder: Option<U::Builder>,
}
/// Errors returned from `Collect` future.
#[derive(Debug)]
pub struct CollectError<T, U> {
inner: Error<T, U>,
}
#[derive(Debug)]
enum Error<T, U> {
Stream(T),
Collect(U),
}
impl<T, U> Collect<T, U>
where
T: BufStream,
U: FromBufStream<T::Item>,
{
pub(crate) fn new(stream: T) -> Collect<T, U> {
let builder = U::builder(&stream.size_hint());
Collect {
stream,
builder: Some(builder),
}
}
}
impl<T, U> Future for Collect<T, U>
where
T: BufStream,
U: FromBufStream<T::Item>,
{
type Item = U;
type Error = CollectError<T::Error, U::Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
let res = self.stream.poll_buf().map_err(|err| {
let inner = Error::Stream(err);
CollectError { inner }
});
match try_ready!(res) {
Some(mut buf) => {
let builder = self.builder.as_mut().expect("cannot poll after done");
U::extend(builder, &mut buf, &self.stream.size_hint()).map_err(|err| {
let inner = Error::Collect(err);
CollectError { inner }
})?;
}
None => {
let builder = self.builder.take().expect("cannot poll after done");
let value = U::build(builder).map_err(|err| {
let inner = Error::Collect(err);
CollectError { inner }
})?;
return Ok(value.into());
}
}
}
}
}
// ===== impl CollectError =====
impl<T, U> CollectError<T, U> {
/// Returns `true` if the error was caused by polling the stream.
pub fn is_stream_err(&self) -> bool {
match self.inner {
Error::Stream(_) => true,
_ => false,
}
}
/// Returns `true` if the error happened while collecting the data.
pub fn is_collect_err(&self) -> bool {
match self.inner {
Error::Collect(_) => true,
_ => false,
}
}
}
-154
View File
@@ -1,154 +0,0 @@
use crate::SizeHint;
use bytes::{Buf, BufMut, Bytes};
use std::error::Error;
use std::fmt;
use std::usize;
/// Conversion from a `BufStream`.
///
/// By implementing `FromBufStream` for a type, you define how it will be
/// created from a buf stream. This is common for types which describe byte
/// storage of some kind.
///
/// `FromBufStream` is rarely called explicitly, and it is instead used through
/// `BufStream`'s `collect` method.
pub trait FromBufStream<T: Buf>: Sized {
/// Type that is used to build `Self` while the `BufStream` is being
/// consumed.
type Builder;
/// Error that might happen on conversion.
type Error;
/// Create a new, empty, builder. The provided `hint` can be used to inform
/// reserving capacity.
fn builder(hint: &SizeHint) -> Self::Builder;
/// Extend the builder with the `Buf`.
///
/// This method is called whenever a new `Buf` value is obtained from the
/// buf stream.
///
/// The provided size hint represents the state of the stream **after**
/// `buf` has been yielded. The lower bound represents the minimum amount of
/// data that will be provided after this call to `extend` returns.
fn extend(builder: &mut Self::Builder, buf: &mut T, hint: &SizeHint)
-> Result<(), Self::Error>;
/// Finalize the building of `Self`.
///
/// Called once the buf stream is fully consumed.
fn build(builder: Self::Builder) -> Result<Self, Self::Error>;
}
/// Error returned from collecting into a `Vec<u8>`
#[derive(Debug)]
pub struct CollectVecError {
_p: (),
}
/// Error returned from collecting into a `Bytes`
#[derive(Debug)]
pub struct CollectBytesError {
_p: (),
}
impl<T: Buf> FromBufStream<T> for Vec<u8> {
type Builder = Vec<u8>;
type Error = CollectVecError;
fn builder(hint: &SizeHint) -> Vec<u8> {
Vec::with_capacity(hint.lower() as usize)
}
fn extend(builder: &mut Self, buf: &mut T, hint: &SizeHint) -> Result<(), Self::Error> {
let lower = hint.lower();
// If the lower bound is greater than `usize::MAX` then we have a
// problem
if lower > usize::MAX as u64 {
return Err(CollectVecError { _p: () });
}
let mut reserve = lower as usize;
// If `upper` is set, use this value if it is less than or equal to 64.
// This only really impacts the first iteration.
match hint.upper() {
Some(upper) if upper <= 64 => {
reserve = upper as usize;
}
_ => {}
}
// hint.lower() represents the minimum amount of data that will be
// received *after* this function call. We reserve this amount on top of
// the amount of data in `buf`.
reserve = match reserve.checked_add(buf.remaining()) {
Some(n) => n,
None => return Err(CollectVecError { _p: () }),
};
// Always reserve 64 bytes the first time, unless `upper` is set and is
// less than 64.
if builder.is_empty() {
reserve = reserve.max(match hint.upper() {
Some(upper) if upper < 64 => upper as usize,
_ => 64,
});
}
// Make sure overflow won't happen when reserving
if reserve.checked_add(builder.len()).is_none() {
return Err(CollectVecError { _p: () });
}
// Reserve space
builder.reserve(reserve);
// Copy the data
builder.put(buf);
Ok(())
}
fn build(builder: Self) -> Result<Self, Self::Error> {
Ok(builder)
}
}
impl<T: Buf> FromBufStream<T> for Bytes {
type Builder = Vec<u8>;
type Error = CollectBytesError;
fn builder(hint: &SizeHint) -> Vec<u8> {
<Vec<u8> as FromBufStream<T>>::builder(hint)
}
fn extend(builder: &mut Vec<u8>, buf: &mut T, hint: &SizeHint) -> Result<(), Self::Error> {
<Vec<u8> as FromBufStream<T>>::extend(builder, buf, hint)
.map_err(|_| CollectBytesError { _p: () })
}
fn build(builder: Vec<u8>) -> Result<Self, Self::Error> {
Ok(builder.into())
}
}
impl fmt::Display for CollectVecError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "BufStream is too big")
}
}
impl Error for CollectVecError {}
impl fmt::Display for CollectBytesError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "BufStream too big")
}
}
impl Error for CollectBytesError {}
-50
View File
@@ -1,50 +0,0 @@
use crate::BufStream;
use bytes::Buf;
use futures::Poll;
use std::error::Error;
use std::fmt;
/// Converts an `Iterator` into a `BufStream` which is always ready to yield the
/// next value.
///
/// Iterators in Rust don't express the ability to block, so this adapter
/// simply always calls `iter.next()` and returns that.
pub fn iter<I>(i: I) -> Iter<I::IntoIter>
where
I: IntoIterator,
I::Item: Buf,
{
Iter {
iter: i.into_iter(),
}
}
/// `BufStream` returned by the [`iter`] function.
#[derive(Debug)]
pub struct Iter<I> {
iter: I,
}
#[derive(Debug)]
pub enum Never {}
impl<I> BufStream for Iter<I>
where
I: Iterator,
I::Item: Buf,
{
type Item = I::Item;
type Error = Never;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
Ok(self.iter.next().into())
}
}
impl fmt::Display for Never {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
unreachable!();
}
}
impl Error for Never {}
-76
View File
@@ -1,76 +0,0 @@
use crate::BufStream;
use bytes::Buf;
use futures::Poll;
/// Limits the stream to a maximum amount of data.
#[derive(Debug)]
pub struct Limit<T> {
stream: T,
remaining: u64,
}
/// Errors returned from `Limit`.
#[derive(Debug)]
pub struct LimitError<T> {
/// When `None`, limit was reached
inner: Option<T>,
}
impl<T> Limit<T> {
pub(crate) fn new(stream: T, amount: u64) -> Limit<T> {
Limit {
stream,
remaining: amount,
}
}
}
impl<T> BufStream for Limit<T>
where
T: BufStream,
{
type Item = T::Item;
type Error = LimitError<T::Error>;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
use futures::Async::Ready;
if self.stream.size_hint().lower() > self.remaining {
return Err(LimitError { inner: None });
}
let res = self
.stream
.poll_buf()
.map_err(|err| LimitError { inner: Some(err) });
match res {
Ok(Ready(Some(ref buf))) => {
if buf.remaining() as u64 > self.remaining {
self.remaining = 0;
return Err(LimitError { inner: None });
}
self.remaining -= buf.remaining() as u64;
}
_ => {}
}
res
}
}
// ===== impl LimitError =====
impl<T> LimitError<T> {
/// Returns `true` if the error was caused by polling the stream.
pub fn is_stream_err(&self) -> bool {
self.inner.is_some()
}
/// Returns `true` if the stream reached its limit.
pub fn is_limit_err(&self) -> bool {
self.inner.is_none()
}
}
-87
View File
@@ -1,87 +0,0 @@
//! Types and utilities for working with `BufStream`.
mod chain;
mod collect;
mod from;
mod iter;
mod limit;
mod stream;
pub use self::chain::Chain;
pub use self::collect::Collect;
pub use self::from::FromBufStream;
pub use self::iter::iter;
pub use self::limit::Limit;
pub use self::stream::{stream, IntoStream};
pub mod error {
//! Error types
pub use super::collect::CollectError;
pub use super::from::{CollectBytesError, CollectVecError};
pub use super::limit::LimitError;
}
use crate::BufStream;
impl<T> BufStreamExt for T where T: BufStream {}
/// An extension trait for `BufStream`'s that provides a variety of convenient
/// adapters.
pub trait BufStreamExt: BufStream {
/// Takes two buf streams and creates a new buf stream over both in
/// sequence.
///
/// `chain()` returns a new `BufStream` value which will first yield all
/// data from `self` then all data from `other`.
///
/// In other words, it links two buf streams together, in a chain.
fn chain<T>(self, other: T) -> Chain<Self, T>
where
Self: Sized,
T: BufStream<Error = Self::Error>,
{
Chain::new(self, other)
}
/// Consumes all data from `self`, storing it in byte storage of type `T`.
///
/// `collect()` returns a future that buffers all data yielded from `self`
/// into storage of type of `T`. The future completes once `self` yield
/// `None`, returning the buffered data.
///
/// The collect future will yield an error if `self` yields an error or if
/// the collect operation errors. The collect error cases are dependent on
/// the target storage type.
fn collect<T>(self) -> Collect<Self, T>
where
Self: Sized,
T: FromBufStream<Self::Item>,
{
Collect::new(self)
}
/// Limit the number of bytes that the stream can yield.
///
/// `limit()` returns a new `BufStream` value which yields all the data from
/// `self` while ensuring that at most `amount` bytes are yielded.
///
/// If `self` can yield greater than `amount` bytes, the returned stream
/// will yield an error.
fn limit(self, amount: u64) -> Limit<Self>
where
Self: Sized,
{
Limit::new(self, amount)
}
/// Creates a `Stream` from a `BufStream`.
///
/// This produces a `Stream` of `BufStream::Items`.
fn into_stream(self) -> IntoStream<Self>
where
Self: Sized,
{
IntoStream::new(self)
}
}
-76
View File
@@ -1,76 +0,0 @@
use crate::BufStream;
use bytes::Buf;
use futures::{Async, Poll, Stream};
/// Converts a `Stream` of `Buf` types into a `BufStream`.
///
/// While `Stream` and `BufStream` are very similar, they are not identical. The
/// `stream` function returns a `BufStream` that is backed by the provided
/// `Stream` type.
pub fn stream<T>(stream: T) -> FromStream<T>
where
T: Stream,
T::Item: Buf,
{
FromStream { stream }
}
/// `BufStream` returned by the [`stream`] function.
#[derive(Debug)]
pub struct FromStream<T> {
stream: T,
}
impl<T> BufStream for FromStream<T>
where
T: Stream,
T::Item: Buf,
{
type Item = T::Item;
type Error = T::Error;
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.stream.poll()
}
}
/// Converts a `BufStream` into a `Stream`.
#[derive(Debug)]
pub struct IntoStream<T> {
buf: T,
}
impl<T> IntoStream<T> {
/// Create a new `Stream` from the provided `BufStream`.
pub fn new(buf: T) -> Self {
IntoStream { buf }
}
/// Get a reference to the inner `BufStream`.
pub fn get_ref(&self) -> &T {
&self.buf
}
/// Get a mutable reference to the inner `BufStream`
pub fn get_mut(&mut self) -> &mut T {
&mut self.buf
}
/// Get the inner `BufStream`.
pub fn into_inner(self) -> T {
self.buf
}
}
impl<T: BufStream> Stream for IntoStream<T> {
type Item = T::Item;
type Error = T::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match self.buf.poll_buf()? {
Async::Ready(Some(buf)) => Ok(Async::Ready(Some(buf))),
Async::Ready(None) => Ok(Async::Ready(None)),
Async::NotReady => Ok(Async::NotReady),
}
}
}
-8
View File
@@ -1,8 +0,0 @@
use tokio_buf::BufStream;
#[test]
fn object_safe() {
// Ensures that `BufStream` can be a trait object
#[allow(dead_code)]
fn obj(_: &mut dyn BufStream<Item = u32, Error = ()>) {}
}
-38
View File
@@ -1,38 +0,0 @@
#![cfg(feature = "broken")]
#![cfg(feature = "util")]
use futures::Async::*;
use tokio_buf::{BufStream, BufStreamExt};
mod support;
use support::*;
#[test]
fn chain() {
// Chain one with one
//
let mut bs = one("hello").chain(one("world"));
assert_buf_eq!(bs.poll_buf(), "hello");
assert_buf_eq!(bs.poll_buf(), "world");
assert_none!(bs.poll_buf());
// Chain multi with multi
let mut bs = list(&["foo", "bar"]).chain(list(&["baz", "bok"]));
assert_buf_eq!(bs.poll_buf(), "foo");
assert_buf_eq!(bs.poll_buf(), "bar");
assert_buf_eq!(bs.poll_buf(), "baz");
assert_buf_eq!(bs.poll_buf(), "bok");
assert_none!(bs.poll_buf());
// Chain includes a not ready call
//
let mut bs = new_mock(&[Ok(Ready("foo")), Ok(NotReady), Ok(Ready("bar"))]).chain(one("baz"));
assert_buf_eq!(bs.poll_buf(), "foo");
assert_not_ready!(bs.poll_buf());
assert_buf_eq!(bs.poll_buf(), "bar");
assert_buf_eq!(bs.poll_buf(), "baz");
assert_none!(bs.poll_buf());
}
-63
View File
@@ -1,63 +0,0 @@
#![cfg(feature = "broken")]
#![cfg(feature = "util")]
use bytes::Bytes;
use futures::Future;
use tokio_buf::BufStreamExt;
mod support;
use support::*;
macro_rules! test_collect_impl {
($t:ty $(, $capacity:ident)*) => {
// While unfortunate, this test makes some assumptions on vec's resizing
// behavior.
//
// Collect one
//
let bs = one("hello world");
let vec: $t = bs.collect().wait().unwrap();
assert_eq!(vec, &b"hello world"[..]);
$( assert_eq!(vec.$capacity(), 64); )*
// Collect one, with size hint
//
let mut bs = one("hello world");
bs.size_hint.set_lower(11);
let vec: $t = bs.collect().wait().unwrap();
assert_eq!(vec, &b"hello world"[..]);
$( assert_eq!(vec.$capacity(), 64); )*
// Collect one, with size hint
//
let mut bs = one("hello world");
bs.size_hint.set_lower(10);
let vec: $t = bs.collect().wait().unwrap();
assert_eq!(vec, &b"hello world"[..]);
$( assert_eq!(vec.$capacity(), 64); )*
// Collect many
//
let bs = list(&["hello", " ", "world", ", one two three"]);
let vec: $t = bs.collect().wait().unwrap();
assert_eq!(vec, &b"hello world, one two three"[..]);
}
}
#[test]
fn collect_vec() {
test_collect_impl!(Vec<u8>, capacity);
}
#[test]
fn collect_bytes() {
test_collect_impl!(Bytes);
}
-29
View File
@@ -1,29 +0,0 @@
#![cfg(feature = "broken")]
use futures::Async::*;
use std::io::Cursor;
use tokio_buf::{util, BufStream};
mod support;
type Buf = Cursor<&'static [u8]>;
#[test]
fn empty_iter() {
let mut bs = util::iter(Vec::<Buf>::new());
assert_none!(bs.poll_buf());
}
#[test]
fn full_iter() {
let bufs = vec![buf(b"one"), buf(b"two"), buf(b"three")];
let mut bs = util::iter(bufs);
assert_buf_eq!(bs.poll_buf(), "one");
assert_buf_eq!(bs.poll_buf(), "two");
assert_buf_eq!(bs.poll_buf(), "three");
assert_none!(bs.poll_buf());
}
fn buf(data: &'static [u8]) -> Buf {
Cursor::new(data)
}
-60
View File
@@ -1,60 +0,0 @@
#![cfg(feature = "broken")]
#![cfg(feature = "util")]
use futures::Async::*;
use futures::Future;
use tokio_buf::{BufStream, BufStreamExt};
mod support;
use support::*;
#[test]
fn limit() {
// Not limited
let res = one("hello world")
.limit(100)
.collect::<Vec<_>>()
.wait()
.unwrap();
assert_eq!(res, b"hello world");
let res = list(&["hello", " ", "world"])
.limit(100)
.collect::<Vec<_>>()
.wait()
.unwrap();
assert_eq!(res, b"hello world");
let res = list(&["hello", " ", "world"])
.limit(11)
.collect::<Vec<_>>()
.wait()
.unwrap();
assert_eq!(res, b"hello world");
// Limited
let res = one("hello world").limit(5).collect::<Vec<_>>().wait();
assert!(res.is_err());
let res = one("hello world").limit(10).collect::<Vec<_>>().wait();
assert!(res.is_err());
let mut bs = list(&["hello", " ", "world"]).limit(9);
assert_buf_eq!(bs.poll_buf(), "hello");
assert_buf_eq!(bs.poll_buf(), " ");
assert!(bs.poll_buf().is_err());
let mut bs = list(&["hello", " ", "world"]);
bs.size_hint.set_lower(11);
let mut bs = bs.limit(9);
assert!(bs.poll_buf().is_err());
}
-40
View File
@@ -1,40 +0,0 @@
use tokio_buf::SizeHint;
#[test]
fn size_hint() {
let hint = SizeHint::new();
assert_eq!(hint.lower(), 0);
assert!(hint.upper().is_none());
let mut hint = SizeHint::new();
hint.set_lower(100);
assert_eq!(hint.lower(), 100);
assert!(hint.upper().is_none());
let mut hint = SizeHint::new();
hint.set_upper(200);
assert_eq!(hint.lower(), 0);
assert_eq!(hint.upper(), Some(200));
let mut hint = SizeHint::new();
hint.set_lower(100);
hint.set_upper(100);
assert_eq!(hint.lower(), 100);
assert_eq!(hint.upper(), Some(100));
}
#[test]
#[should_panic]
fn size_hint_lower_bigger_than_upper() {
let mut hint = SizeHint::new();
hint.set_upper(100);
hint.set_lower(200);
}
#[test]
#[should_panic]
fn size_hint_upper_less_than_lower() {
let mut hint = SizeHint::new();
hint.set_lower(200);
hint.set_upper(100);
}
-44
View File
@@ -1,44 +0,0 @@
#![cfg(feature = "broken")]
use futures::sync::mpsc;
use futures::Async::*;
use std::io::Cursor;
use tokio_buf::{util, BufStream};
use tokio_mock_task::MockTask;
mod support;
type Buf = Cursor<&'static [u8]>;
#[test]
fn empty_stream() {
let (_, rx) = mpsc::unbounded::<Buf>();
let mut bs = util::stream(rx);
assert_none!(bs.poll_buf());
}
#[test]
fn full_stream() {
let (tx, rx) = mpsc::unbounded();
let mut bs = util::stream(rx);
let mut task = MockTask::new();
tx.unbounded_send(buf(b"one")).unwrap();
assert_buf_eq!(bs.poll_buf(), "one");
task.enter(|| assert_not_ready!(bs.poll_buf()));
tx.unbounded_send(buf(b"two")).unwrap();
assert!(task.is_notified());
assert_buf_eq!(bs.poll_buf(), "two");
task.enter(|| assert_not_ready!(bs.poll_buf()));
drop(tx);
assert!(task.is_notified());
assert_none!(bs.poll_buf());
}
fn buf(data: &'static [u8]) -> Buf {
Cursor::new(data)
}
-34
View File
@@ -1,34 +0,0 @@
#![cfg(feature = "broken")]
use futures::Async::*;
use std::fmt;
use tokio_buf::BufStream;
mod support;
fn test_hello_world<B>(mut bs: B)
where
B: BufStream + fmt::Debug,
B::Item: fmt::Debug,
B::Error: fmt::Debug,
{
let hint = bs.size_hint();
assert_eq!(hint.lower(), 11);
assert_eq!(hint.upper(), Some(11));
assert_buf_eq!(bs.poll_buf(), "hello world");
let hint = bs.size_hint();
assert_eq!(hint.lower(), 0);
assert_eq!(hint.upper(), Some(0));
assert_none!(bs.poll_buf());
}
#[test]
fn string() {
test_hello_world("hello world".to_string());
}
#[test]
fn str() {
test_hello_world("hello world");
}
-133
View File
@@ -1,133 +0,0 @@
#![cfg(feature = "broken")]
#![allow(unused)]
use bytes::Buf;
use futures::Async::*;
use futures::Poll;
use tokio_buf::{BufStream, SizeHint};
use std::collections::VecDeque;
use std::io::Cursor;
#[macro_export]
macro_rules! assert_buf_eq {
($actual:expr, $expect:expr) => {{
use bytes::Buf;
match $actual {
Ok(Ready(Some(val))) => {
assert_eq!(val.remaining(), val.bytes().len());
assert_eq!(val.bytes(), $expect.as_bytes());
}
Ok(Ready(None)) => panic!("expected value; BufStream yielded None"),
Ok(NotReady) => panic!("expected value; BufStream is not ready"),
Err(e) => panic!("expected value; got error = {:?}", e),
}
}};
}
#[macro_export]
macro_rules! assert_none {
($actual:expr) => {
match $actual {
Ok(Ready(None)) => {}
actual => panic!("expected None; actual = {:?}", actual),
}
};
}
#[macro_export]
macro_rules! assert_not_ready {
($actual:expr) => {
match $actual {
Ok(NotReady) => {}
actual => panic!("expected NotReady; actual = {:?}", actual),
}
};
}
// ===== Test utils =====
pub fn one(buf: &'static str) -> Mock {
list(&[buf])
}
pub fn list(bufs: &[&'static str]) -> Mock {
let mut polls = VecDeque::new();
for &buf in bufs {
polls.push_back(Ok(Ready(buf.as_bytes())));
}
Mock {
polls,
size_hint: SizeHint::default(),
}
}
pub fn new_mock(values: &[Poll<&'static str, ()>]) -> Mock {
let mut polls = VecDeque::new();
for &v in values {
polls.push_back(match v {
Ok(Ready(v)) => Ok(Ready(v.as_bytes())),
Ok(NotReady) => Ok(NotReady),
Err(e) => Err(e),
});
}
Mock {
polls,
size_hint: SizeHint::default(),
}
}
#[derive(Debug)]
pub struct Mock {
pub polls: VecDeque<Poll<&'static [u8], ()>>,
pub size_hint: SizeHint,
}
#[derive(Debug)]
pub struct MockBuf {
pub data: Cursor<&'static [u8]>,
}
impl BufStream for Mock {
type Item = MockBuf;
type Error = ();
fn poll_buf(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match self.polls.pop_front() {
Some(Ok(Ready(value))) => Ok(Ready(Some(MockBuf::new(value)))),
Some(Ok(NotReady)) => Ok(NotReady),
Some(Err(e)) => Err(e),
None => Ok(Ready(None)),
}
}
fn size_hint(&self) -> SizeHint {
self.size_hint.clone()
}
}
impl MockBuf {
fn new(data: &'static [u8]) -> MockBuf {
MockBuf {
data: Cursor::new(data),
}
}
}
impl Buf for MockBuf {
fn remaining(&self) -> usize {
self.data.remaining()
}
fn bytes(&self) -> &[u8] {
self.data.bytes()
}
fn advance(&mut self, cnt: usize) {
self.data.advance(cnt)
}
}
-22
View File
@@ -1,22 +0,0 @@
# 0.2.0-alpha.3 (August 28, 2019)
### Fix
- Infinite loop in `LinesCodec` (#1489).
# 0.2.0-alpha.2 (August 17, 2019)
### Changed
- Update `futures` dependency to 0.3.0-alpha.18.
# 0.2.0-alpha.1 (August 8, 2019)
### Changed
- Switch to `async`, `await`, and `std::future`.
# 0.1.1 (September 26, 2018)
* Allow setting max line length with `LinesCodec` (#632)
# 0.1.0 (June 13, 2018)
* Initial release (#353)
-37
View File
@@ -1,37 +0,0 @@
[package]
name = "tokio-codec"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "v0.2.x" git tag.
version = "0.2.0-alpha.3"
edition = "2018"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-codec/0.2.0-alpha.3/tokio_codec"
description = """
Utilities for encoding and decoding frames.
"""
categories = ["asynchronous"]
[dependencies]
tokio-io = { version = "=0.2.0-alpha.3", path = "../tokio-io" }
bytes = "0.4.7"
futures-core-preview = "=0.3.0-alpha.18"
futures-sink-preview = "=0.3.0-alpha.18"
log = "0.4"
[dev-dependencies]
tokio = { version = "=0.2.0-alpha.3", path = "../tokio" }
tokio-test = { version = "=0.2.0-alpha.3", path = "../tokio-test" }
futures-util-preview = "=0.3.0-alpha.18"
[package.metadata.docs.rs]
all-features = true
-25
View File
@@ -1,25 +0,0 @@
Copyright (c) 2019 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-40
View File
@@ -1,40 +0,0 @@
use crate::decoder::Decoder;
use crate::encoder::Encoder;
use bytes::{BufMut, Bytes, BytesMut};
use std::io;
/// A simple `Codec` implementation that just ships bytes around.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
pub struct BytesCodec(());
impl BytesCodec {
/// Creates a new `BytesCodec` for shipping around raw bytes.
pub fn new() -> BytesCodec {
BytesCodec(())
}
}
impl Decoder for BytesCodec {
type Item = BytesMut;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<BytesMut>, io::Error> {
if !buf.is_empty() {
let len = buf.len();
Ok(Some(buf.split_to(len)))
} else {
Ok(None)
}
}
}
impl Encoder for BytesCodec {
type Item = Bytes;
type Error = io::Error;
fn encode(&mut self, data: Bytes, buf: &mut BytesMut) -> Result<(), io::Error> {
buf.reserve(data.len());
buf.put(data);
Ok(())
}
}
-40
View File
@@ -1,40 +0,0 @@
#![doc(html_root_url = "https://docs.rs/tokio-codec/0.2.0-alpha.3")]
#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unreachable_pub
)]
#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]
//! Utilities for encoding and decoding frames.
//!
//! Contains adapters to go from streams of bytes, [`AsyncRead`] and
//! [`AsyncWrite`], to framed streams implementing [`Sink`] and [`Stream`].
//! Framed streams are also known as transports.
//!
//! [`AsyncRead`]: https://docs.rs/tokio/*/tokio/io/trait.AsyncRead.html
//! [`AsyncWrite`]: https://docs.rs/tokio/*/tokio/io/trait.AsyncWrite.html
//! [`Sink`]: https://docs.rs/futures-sink-preview/*/futures_sink/trait.Sink.html
//! [`Stream`]: https://docs.rs/futures-core-preview/*/futures_core/stream/trait.Stream.html
#[macro_use]
mod macros;
mod bytes_codec;
mod decoder;
mod encoder;
mod framed;
mod framed_read;
mod framed_write;
pub mod length_delimited;
mod lines_codec;
pub use crate::bytes_codec::BytesCodec;
pub use crate::decoder::Decoder;
pub use crate::encoder::Encoder;
pub use crate::framed::{Framed, FramedParts};
pub use crate::framed_read::FramedRead;
pub use crate::framed_write::FramedWrite;
pub use crate::length_delimited::{LengthDelimitedCodec, LengthDelimitedCodecError};
pub use crate::lines_codec::{LinesCodec, LinesCodecError};
-7
View File
@@ -1,7 +0,0 @@
/// A macro to reduce some of the boilerplate for projecting from
/// `Pin<&mut T>` to `Pin<&mut T.field>`
macro_rules! pin {
($e:expr) => {
std::pin::Pin::new(&mut $e)
};
}
-67
View File
@@ -1,67 +0,0 @@
# 0.2.0-alpha.3 (August 28, 2019)
### Changed
- use `tracing` instead of `log`
### Added
- thread pool dedicated to blocking operations (#1495).
- `Executor::spawn_with_handle` (#1492).
# 0.2.0-alpha.2 (August 17, 2019)
### Fixed
- allow running executor from within blocking clause (#1433).
### Changed
- Update `futures` dependency to 0.3.0-alpha.18.
### Added
- Import `current-thread` executor (#1447).
- Import `threadpool` executor (#1152).
# 0.2.0-alpha.1 (August 8, 2019)
### Changed
- Switch to `async`, `await`, and `std::future`.
### Removed
- `Enter::make_permanent` and `Enter::on_exit` (#???)
# 0.1.7 (March 22, 2019)
### Added
- `TypedExecutor` for spawning futures of a specific type (#993).
# 0.1.6 (January 6, 2019)
* Implement `Unpark` for `Arc<Unpark>` (#802).
* Switch to crossbeam's Parker / Unparker (#528).
# 0.1.5 (September 26, 2018)
* Implement `futures::Executor` for `DefaultExecutor` (#563).
* Add `Enter::block_on(future)` (#646)
# 0.1.4 (August 23, 2018)
* Implement `std::error::Error` for error types (#511).
# 0.1.3 (August 6, 2018)
* Implement `Executor` for `Box<E: Executor>` (#420).
* Improve `EnterError` debug message (#410).
* Implement `status`, `Send`, and `Sync` for `DefaultExecutor` (#463, #472).
* Fix race in `ParkThread` (#507).
* Handle recursive calls into `DefaultExecutor` (#473).
# 0.1.2 (March 30, 2018)
* Implement `Unpark` for `Box<Unpark>`.
# 0.1.1 (March 22, 2018)
* Optionally support futures 0.2.
# 0.1.0 (March 09, 2018)
* Initial release
-63
View File
@@ -1,63 +0,0 @@
[package]
name = "tokio-executor"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "v0.2.x" git tag.
version = "0.2.0-alpha.3"
edition = "2018"
documentation = "https://docs.rs/tokio-executor/0.2.0-alpha.3/tokio_executor"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://github.com/tokio-rs/tokio"
license = "MIT"
authors = ["Tokio Contributors <[email protected]>"]
description = """
Future execution primitives
"""
keywords = ["futures", "tokio"]
categories = ["concurrency", "asynchronous"]
[features]
blocking = ["tokio-sync", "lazy_static"]
current-thread = ["crossbeam-channel"]
threadpool = [
"tokio-sync",
"crossbeam-deque",
"crossbeam-queue",
"crossbeam-utils",
"futures-core-preview",
"num_cpus",
"lazy_static",
"slab",
]
[dependencies]
tokio-sync = { version = "=0.2.0-alpha.3", optional = true, path = "../tokio-sync" }
tracing = { version = "0.1.5", optional = true }
futures-util-preview = { version = "=0.3.0-alpha.18", features = ["channel"] }
# current-thread dependencies
crossbeam-channel = { version = "0.3.8", optional = true }
# threadpool dependencies
crossbeam-deque = { version = "0.7.0", optional = true }
crossbeam-queue = { version = "0.1.0", optional = true }
crossbeam-utils = { version = "0.6.4", optional = true }
futures-core-preview = { version = "=0.3.0-alpha.18", optional = true }
num_cpus = { version = "1.2", optional = true }
lazy_static = { version = "1", optional = true }
slab = { version = "0.4.1", optional = true }
[dev-dependencies]
tokio = { version = "0.2.0-alpha.3", path = "../tokio" }
tokio-test = { version = "0.2.0-alpha.3", path = "../tokio-test" }
futures-core-preview = "=0.3.0-alpha.18"
rand = "0.7"
[package.metadata.docs.rs]
all-features = true
-25
View File
@@ -1,25 +0,0 @@
Copyright (c) 2019 Tokio Contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-13
View File
@@ -1,13 +0,0 @@
# tokio-executor
Task execution related traits and utilities.
## License
This project is licensed under the [MIT license](LICENSE).
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Tokio by you, shall be licensed as MIT, without any additional
terms or conditions.
-132
View File
@@ -1,132 +0,0 @@
#![feature(test)]
#![warn(rust_2018_idioms)]
extern crate test;
const ITER: usize = 1_000;
mod blocking {
use super::*;
use futures::future::*;
use tokio_executor::threadpool::{blocking, Builder};
#[bench]
fn cpu_bound(b: &mut test::Bencher) {
let pool = Builder::new().pool_size(2).max_blocking(20).build();
b.iter(|| {
let count_down = Arc::new(CountDown::new(ITER));
for _ in 0..ITER {
let count_down = count_down.clone();
pool.spawn(lazy(move || {
poll_fn(|| blocking(|| perform_complex_computation()).map_err(|_| panic!()))
.and_then(move |_| {
// Do something with the value
count_down.dec();
Ok(())
})
}));
}
count_down.wait();
})
}
}
mod message_passing {
use super::*;
use futures::future::*;
use futures::sync::oneshot;
use tokio_executor::threadpool::Builder;
#[bench]
fn cpu_bound(b: &mut test::Bencher) {
let pool = Builder::new().pool_size(2).max_blocking(20).build();
let blocking = threadpool::ThreadPool::new(20);
b.iter(|| {
let count_down = Arc::new(CountDown::new(ITER));
for _ in 0..ITER {
let count_down = count_down.clone();
let blocking = blocking.clone();
pool.spawn(lazy(move || {
// Create a channel to receive the return value.
let (tx, rx) = oneshot::channel();
// Spawn a task on the blocking thread pool to process the
// computation.
blocking.execute(move || {
let res = perform_complex_computation();
tx.send(res).unwrap();
});
rx.and_then(move |_| {
count_down.dec();
Ok(())
})
.map_err(|_| panic!())
}));
}
count_down.wait();
})
}
}
fn perform_complex_computation() -> usize {
use rand::*;
// Simulate a CPU heavy computation
let mut rng = rand::thread_rng();
rng.gen()
}
// Util for waiting until the tasks complete
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::*;
use std::sync::*;
struct CountDown {
rem: AtomicUsize,
mutex: Mutex<()>,
condvar: Condvar,
}
impl CountDown {
fn new(rem: usize) -> Self {
CountDown {
rem: AtomicUsize::new(rem),
mutex: Mutex::new(()),
condvar: Condvar::new(),
}
}
fn dec(&self) {
let prev = self.rem.fetch_sub(1, AcqRel);
if prev != 1 {
return;
}
let _lock = self.mutex.lock().unwrap();
self.condvar.notify_all();
}
fn wait(&self) {
let mut lock = self.mutex.lock().unwrap();
loop {
if self.rem.load(Acquire) == 0 {
return;
}
lock = self.condvar.wait(lock).unwrap();
}
}
}
-160
View File
@@ -1,160 +0,0 @@
#![feature(test)]
#![warn(rust_2018_idioms)]
extern crate test;
const NUM_SPAWN: usize = 10_000;
const NUM_YIELD: usize = 1_000;
const TASKS_PER_CPU: usize = 50;
mod threadpool {
use futures::{future, task, Async};
use num_cpus;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::{mpsc, Arc};
use tokio_executor::threadpool::*;
#[bench]
fn spawn_many(b: &mut test::Bencher) {
let threadpool = ThreadPool::new();
let (tx, rx) = mpsc::sync_channel(10);
let rem = Arc::new(AtomicUsize::new(0));
b.iter(move || {
rem.store(super::NUM_SPAWN, SeqCst);
for _ in 0..super::NUM_SPAWN {
let tx = tx.clone();
let rem = rem.clone();
threadpool.spawn(future::lazy(move || {
if 1 == rem.fetch_sub(1, SeqCst) {
tx.send(()).unwrap();
}
Ok(())
}));
}
let _ = rx.recv().unwrap();
});
}
#[bench]
fn yield_many(b: &mut test::Bencher) {
let threadpool = ThreadPool::new();
let tasks = super::TASKS_PER_CPU * num_cpus::get();
let (tx, rx) = mpsc::sync_channel(tasks);
b.iter(move || {
for _ in 0..tasks {
let mut rem = super::NUM_YIELD;
let tx = tx.clone();
threadpool.spawn(future::poll_fn(move || {
rem -= 1;
if rem == 0 {
tx.send(()).unwrap();
Ok(Async::Ready(()))
} else {
// Notify the current task
task::current().notify();
// Not ready
Ok(Async::NotReady)
}
}));
}
for _ in 0..tasks {
let _ = rx.recv().unwrap();
}
});
}
}
// In this case, CPU pool completes the benchmark faster, but this is due to how
// CpuPool currently behaves, starving other futures. This completes the
// benchmark quickly but results in poor runtime characteristics for a thread
// pool.
//
// See rust-lang-nursery/futures-rs#617
//
mod cpupool {
use futures::future::{self, Executor};
use futures::{task, Async};
use futures_cpupool::*;
use num_cpus;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::{mpsc, Arc};
#[bench]
fn spawn_many(b: &mut test::Bencher) {
let pool = CpuPool::new(num_cpus::get());
let (tx, rx) = mpsc::sync_channel(10);
let rem = Arc::new(AtomicUsize::new(0));
b.iter(move || {
rem.store(super::NUM_SPAWN, SeqCst);
for _ in 0..super::NUM_SPAWN {
let tx = tx.clone();
let rem = rem.clone();
pool.execute(future::lazy(move || {
if 1 == rem.fetch_sub(1, SeqCst) {
tx.send(()).unwrap();
}
Ok(())
}))
.ok()
.unwrap();
}
let _ = rx.recv().unwrap();
});
}
#[bench]
fn yield_many(b: &mut test::Bencher) {
let pool = CpuPool::new(num_cpus::get());
let tasks = super::TASKS_PER_CPU * num_cpus::get();
let (tx, rx) = mpsc::sync_channel(tasks);
b.iter(move || {
for _ in 0..tasks {
let mut rem = super::NUM_YIELD;
let tx = tx.clone();
pool.execute(future::poll_fn(move || {
rem -= 1;
if rem == 0 {
tx.send(()).unwrap();
Ok(Async::Ready(()))
} else {
// Notify the current task
task::current().notify();
// Not ready
Ok(Async::NotReady)
}
}))
.ok()
.unwrap();
}
for _ in 0..tasks {
let _ = rx.recv().unwrap();
}
});
}
}

Some files were not shown because too many files have changed in this diff Show More