Compare commits

...
1111 Commits
Author SHA1 Message Date
Alice Ryhl 492650b1f1 chore: prepare tokio-uds v0.2.7 release (#2638) 2020-07-01 22:30:08 +02:00
Joshua M. Clulow 653007a0a5 uds: illumos can build using existing Solaris support (#2563) 2020-07-01 19:37:09 +02:00
Taiki Endo 048628bab5 ci: fix ci failure on v0.1.x (#2608) 2020-06-11 17:58:54 +09:00
John-John Tedro e096857bc2 Fix broken links to tokio::net (#2220) 2020-02-05 10:03:26 -05:00
Lucio Franco 367511dc6b udp: Fix warning with unused paren (#2219)
Signed-off-by: Lucio Franco <[email protected]>
2020-02-04 18:48:36 -05:00
Lucio Franco 8fddd4cb86 chore: Prepare final 0.1.x release (#2216)
Signed-off-by: Lucio Franco <[email protected]>
2020-02-04 17:43:02 -05:00
Avery Harnish a05e5a7723 docs: fix typos in blocking example (#2115) 2020-01-24 11:34:33 -08:00
Qinxuan Chen 93cc30d051 Prune duplicate crossbeam dependencies (#1795)
Signed-off-by: koushiro <[email protected]>
2020-01-20 17:01:06 -05:00
John-John Tedro 0f11d56a3c More deprecation notices (relates #2036) (#2098) 2020-01-14 15:36:16 -05:00
Ivan Petkov 86de4baacc v0.1.x: ci: test tokio-process (#2101) 2020-01-13 20:50:47 -08:00
John-John Tedro 8576df240d process: Add deprecation warning (relates #2036) 2020-01-12 01:48:57 +01:00
John-John Tedro a58f218c1d Re-merge tokio-process into tokio v0.1.x 2020-01-12 01:03:25 +01:00
John-John Tedro c22e4f6597 Add deprecation notices for outdated crates (#2036) (#2097)
* Add deprecation notices for outdated crates (#2036)

* Add notice about renaming reactor
2020-01-11 11:19:10 -08:00
Eliza Weisman da17125316 v0.1.x: prepare to release tokio-threadpool 0.1.17 (#1893)
0.1.17 (December 3, 2019)

Added
- Internal APIs for overriding blocking behavior (#1752)

Signed-off-by: Eliza Weisman <[email protected]>
2019-12-04 13:58:09 -08:00
Eliza Weisman 97565c0e75 v0.1.x: prepare to release new reactor, executor, and timer (#1751) 2019-11-27 12:52:42 -08:00
George Hahn 96b014c12a Allow access to CurrentThread executor handle (#1809)
## Motivation

The `CurrentThread` runtime's `Handle` is different than the
`CurrentThread` executor's `Handle`. This causes interoperability issues
with custom runtimes that build on the `CurrentThread` executor.

Actix-rt offers a concrete example of the issue: [`System::run_in_executor`][1]
requires a `CurrentThread` executor handle - the change in this PR
allows a `CurrentThread` runtime to be used here.

## Solution

This PR adds `fn into_inner(self)` on the runtime `Handle` that consumes
it and returns the underlying `CurrentThread` executor's `Handle`.

[1]: https://docs.rs/actix-rt/0.2.6/actix_rt/struct.System.html#method.run_in_executor
2019-11-27 12:10:20 -08:00
Ben Boeckel b0a90d88cd v0.1.x: tokio: bump minimum versions (#1764)
tokio-uds 0.2.4 has the `UnixDatagramFramed` which is reexported here
and tokio-threadpool 0.1.16 uses a new enough rand that compiles with
modern toolchains.
2019-11-26 13:57:56 -08:00
Eliza Weisman 9e91b8d87e v0.1.x: allow overriding blocking behavior (#1752)
## Motivation

The initial version of `tokio-compat`'s compatibility runtime added in
#1663 doesn't support the calls to `tokio_threadpool` 0.1's `blocking`.
This is because (unlike the timer, executor, and reactor), there's no
way to override the global `blocking` functionality in
`tokio-threadpool`.

## Solution

As discussed [here][1], this branch adds APIs to the v0.1.x version of
`tokio-threadpool` that allow overriding the behavior used by calls to
`blocking`. The threadpool crate now exposes `blocking::set_default` and
`blocking::with_default` functions, like `executor`, `timer`, and
`reactor`. This will allow `tokio-compat` to override calls to 0.1's
`blocking` to use the new `tokio` 0.2 blocking APIs.

Unlike the similar APIs in `executor`, `timer`, and `reactor`, the hooks
for overriding blocking behaviour are `#[doc(hidden)]` and have comments
warning against their use outside of `tokio-compat`. In general, there 
probably won't be a compelling reason to override these outside of the 
compatibility layer.

Refs: #1722

[1]: https://github.com/tokio-rs/tokio/pull/1663#issuecomment-548661766

Signed-off-by: Eliza Weisman <[email protected]>
2019-11-12 14:38:55 -08:00
Eliza Weisman 22b7bd2f51 [0.1.x] add set_default to 0.1 executor, timer, and reactor (#1725)
This commit adds `set_default` drop guard style APIs for setting the
default reactor, executor, and timer. These are similar to the APIs used
in `tokio` 0.2

In addition to having potentially better ergonomics than the
`with_default` closure APIs, the drop-guard based APIs will be helpful
in rewriting the `tokio-compat` crate to wrap the existing tokio 0.2
runtime, rather than constructing its own runtime.

Because the runtime does not expose an `around_worker` API, it cannot
currently be used with the 0.1 `with_default` method of setting the
reactor, timer, and executor. This means that tokio-compat must
duplicate a lot of existing code from `tokio` to construct the runtime,
which is unfortunate (and has the potential to introduce errors). On the
other hand, we can use the drop guard APIs with `before_start` and
`after_stop`, by storing the drop guards in a thread-local. This will
allow `tokio-compat` to wrap the 0.2 runtime, reducing code duplication.
Also, this will allow the blocking pool to be used on the compat
runtime, which is currently impossible (as the blocking APIs are private
to `tokio`).

Signed-off-by: Eliza Weisman <[email protected]>
2019-11-06 15:53:33 -08:00
Eliza Weisman 23ecc2b5eb [0.1.x] chore: remove old async-await support (#1742)
## Motivation

Currently, the tests for `tokio` 0.1's async-await support build against a 
fairly old nightly from Rust 1.36. Upstream changes to a transitive 
dependency introduced a use of `MaybeUninit`, which is feature 
flagged on this nightly. This resultedin [0.1.x builds breaking][1].

The `tokio` 0.1 async-await support has not been maintained, in favour
of working on 0.2. It currently uses severely outdated versions of the
async-await APIs (including the `await!` macro). Anyone using
async-await with Tokio is almsot certainly on 0.2 by now.

## Solution

Since the 0.1 async-await APIs are both unused and unmaintained, this
branch deletes them.

[1]: https://dev.azure.com/tokio-rs/Tokio/_build/results?buildId=3174&view=logs&jobId=ba363064-0d45-526e-6c63-c7e816804fbe&taskId=3aff0ee6-e312-56d4-f5d3-d804e6c343c3&lineStart=83&lineEnd=87&colStart=1&colEnd=1

Signed-off-by: Eliza Weisman <[email protected]>
2019-11-06 14:11:24 -08:00
Carl Lerche da186a7859 prepare tokio-sync v0.1.7 release. (#1650) 2019-10-10 13:16:36 -07:00
Carl Lerche 2117ce7bac sync: fix mem leak in oneshot on task migration (#1649)
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.

Backport of #1648.
2019-10-10 12:47:53 -07:00
David Kellum 39f369f686 v0.1.x: Don't deny warnings (#1368)
This is just too aggressive for a stable maintenance branch of tokio,
in that new rust release warnings are prooving too hard to fix.
2019-09-30 18:28:26 -04:00
Lucio Franco 83e8fff090 reactor: Remove extra semi colon (#1616)
* reactor: Remove extra semi colon

* fmt
2019-09-30 15:06:17 -04:00
David Kellum f545d1276b v0.1.x: stage -threadpool 0.1.16 -reactor 0.1.10 releases (#1604)
* upgrade to rand 0.7.0 (MSRV 1.32)

* upgrade to parking_lot 0.9.0

* Remove last non-dev dependency on rand crate (#1324)

Use std RandomState for XorShift seeding. This allows dropping _rand_
crate dep here, accept as a dev dependency for tests or benchmarks.

* increase CI MSRV to 1.31.0

* increase nightly for CI TSAN tests

* add TSAN suppressions for recent rand related updates

* make latest TSAN suppression patterns more general

* upgrade tempfile dev dep for common rand version

But avoid tempfile 3.2 for now, since history demonstrates it bumps
rand versions and MSRV in MINOR updates.

* update (dev dep) env_logger to latest 0.6

* reactor, threadpool: bump PATCH versions, doc links, change logs [ci-release]
2019-09-30 14:21:56 -04:00
Roman Proskuryakov 59fb5b9a7d Add more unit tests for UdpFramed (#1522) 2019-08-30 22:29:02 -04:00
Lucio Franco 57ba3a7fbc udp: Prep release v0.1.5 (#1519)
Signed-off-by: Lucio Franco <[email protected]>
2019-08-30 17:51:48 -04:00
Lucio Franco c3c3481d74 udp: Fix UdpFramed decode (#1517) 2019-08-30 11:13:54 -07:00
Lucio Franco 7b39388415 Prep tokio-udp 0.1.4 release (#1503)
* Fix warnings in udp tests

* Prep tokio-udp 0.1.4 release
2019-08-28 12:16:40 -04:00
John Doneth 11a1ce2721 v0.1.x: Fix UdpFramed with regards to Decode (#1444)
* add test for using LinesCodec with UdpFramed

* fix UdpFramed decode

* rustfmt
2019-08-20 15:57:04 -04:00
David Kellum c9532e49d7 v0.1.x lint fix, MSRV 1.28.0 updates (#1451)
* use dyn Trait syntax where appropriate

recent rust nightly started warning that not using `dyn` was
deprecated. This requires MSRV 1.27.0+.

* rustfmt fallout from dyn additions

* stop explicit allow of rust_2018_idioms

* more dyn Trait syntax

* drop tokio-macros from 0.1.x workspace

Since tokio-macros specifies an edition=2018, we would otherwise
require MSRV 1.31.0 to build/test it. And tokio-macros isn't used with
tokio 0.1.x.

* reactor: narrow tokio-io-pool dev dep to 0.1.4

Since 0.1.5-6 is now a edition=2018 crate, which has effective MSRV
1.31.0.

* narrow tempfile dev-dep to avoid MSRV bump

tempfile 3.1.0 pulls in rand 0.7.0 and is MSRV 1.32.0

* narrow flate2 dev-dep to avoid MSRV bump

flate2 1.0.10-11 have MSRV 1.34.0.

github refs: alexcrichton/flate2-rs#207

* fs: drop deprecated tempdir crate use in tests

In particular because it pulls in old rand duplicates. Replace use
with tempfile::tempdir() which has been available since tempfile
3.0.0.

backport-of: #1312

* increase CI MSRV to 1.28.0
2019-08-15 18:28:56 -04:00
Jon Gjengset b4cb3226ab Bump 0.1 versions for latest changes (#1240)
[ci-release]
2019-07-03 09:21:33 -07:00
Eliza Weisman 4446eb4db8 chore: remove tokio-trace, add "Related Projects" to README (v0.1) (#1223)
* chore: remove `tokio-trace`, add "Related Projects" to README (#1221)

The `tokio-trace` and `tokio-trace-core` crates have been renamed to
`tracing` and `tracing-core`, and moved to their own repository
(`tokio-rs/tracing`).

This branch removes `tokio-trace` and `tokio-trace-core` from the
`tokio` repository. In addition, I've added a "Related Projects" section
to the root README, which lists `tracing` (as well as  `mio`, and
`bytes`) as other libraries maintained by the Tokio project. I thought
that this would help folks looking for `tokio-trace` here find it in its
new home.

In addition, it changes `tokio` to depend on `tracing-core` rather than
`tokio-trace-core`.

Closes #1159

Signed-off-by: Eliza Weisman <[email protected]>

* Remove erroneous add of `tokio-macros`

* Some more tokio-trace remnants

* Remove tokio-trace remnants from Cirrus CI

* disable tracing-core feature by default

It can't build on Rust 1.26.0

Signed-off-by: Eliza Weisman <[email protected]>

* fix feature flagging

Signed-off-by: Eliza Weisman <[email protected]>
2019-07-01 16:18:12 -07:00
Sean McArthur cad0c35623 executor: add executor::exit (#1155)
This allows blocking on executors from within a `threadpool::blocking` call.
2019-06-24 09:22:54 -07:00
Kevin Leimkuhler 5dcb379f6d Bump tokio-sync to 0.1.6 (#1123) 2019-06-05 12:19:06 -07:00
Kevin Leimkuhler 970f75f830 sync: Add Sync impl for Lock (#1117) 2019-06-04 17:04:35 -07:00
Carl Lerche 01052f930a Bump tokio version to v0.1.21. (#1113) 2019-05-30 14:39:30 -07:00
Lucio Franco 940f2c3431 Update tokio-trace-core to 0.2 (#1111)
Also includes 1b498e8aa2
2019-05-30 11:33:55 -07:00
Carl Lerche 475dabe96d Release tokio v0.1.20, tokio-timer v0.2.21, and remove async-await-preview feature. (#1089)
The `async-await-preview` feature is removed as 0.1 will no longer track
Rust nightly.

This also bumps:
- tokio-timer (0.2.11).
2019-05-14 11:21:24 -07:00
Carl Lerche 951f2fd910 test: re-export macro dependencies (#1077)
Callers may not always have `futures` available at the root of the
crate. Re-exporting dependencies makes them available to the macro at a
deterministic location.
2019-05-03 20:43:40 -07:00
Carl Lerche 4ef736b9d5 async-await: add current_thread::Runtime::block_on_async (#1072)
This function is used by the Tokio macros introduced by #1058  but was
omitted from the PR.
2019-04-30 19:55:22 -07:00
Steven Fackler 219f24cbf1 timer: Replace Handle::deadline with Handle::timeout (#1074)
Deadline was deprecated a while ago and replaced with Timeout, but the
methods on Handle got missed.

Fixes #1071
2019-04-30 10:29:54 -07:00
Carl Lerche ea282efb2e ci: fix isRelease condition (#1066) 2019-04-29 10:37:00 -07:00
Michal 'vorner' Vaner 042224d33c signal: Smaller dependency (#1069)
The signal-hook library got split into lower-level and higher-level
parts. The tokio-signal uses only API from the lower-level one, so it
can depend on it directly.

The only effect of this change is smaller amount of compiled (and
unused) code during compilation. There's no change in the code actually
used.
2019-04-28 19:12:40 -07:00
Ian Hamlin 927eb80ad4 Fix an error in the mit-url in the README.md (#1068) 2019-04-27 12:56:40 -07:00
Carl Lerche 6a8934e897 Fix threadpool dependency (#1061) 2019-04-25 22:23:24 -04:00
Carl Lerche 0e400af78c Async/await polish (#1058)
A general refresh of Tokio's experimental async / await support.
2019-04-25 22:22:32 -04:00
Carl Lerche df702130d6 tcp: fix some tests that spuriously fail (#1060)
This does not remove all cases of using a fixed port in doc tests, but
removing some should reduce the likelihood of spurious failures.
2019-04-25 12:01:39 -07:00
Carl Lerche 949adbb887 chore: remember to remove path deps on release (#1057) 2019-04-24 10:42:39 -07:00
Ryan Dahl b2b796a228 rt: forward panic_handler to tokio::runtime::Builder (#1055) 2019-04-24 10:41:42 -07:00
Igor Gnatenko abb014efc2 tokio: Bump min version of tokio-sync (#1054)
It is needed for lock functionality which tokio now uses.
2019-04-24 08:24:59 -07:00
Lucio Franco e5cf0cc717 Introduce tokio-test crate (#1030) 2019-04-23 20:17:57 -07:00
Carl Lerche 62f34e15ce Bump tokio to 0.1.19. (#1053)
This also bumps:

- tokio-async-await (0.1.7)
- tokio-buf (0.1.1)
- tokio-sync (0.1.5)
- tokio-threadpool (0.1.14)
2019-04-22 15:12:25 -07:00
Eliza Weisman 3ebca76a9a trace: prepare tokio-trace for release (#1051) 2019-04-22 14:15:07 -07:00
Ryan Dahl fea1f780bc threadpool: add panic_handler (#1052) 2019-04-21 16:26:09 -07:00
Eliza Weisman 712ca84033 trace-core: prepare for 0.2 release (#1047) 2019-04-21 10:20:28 -07:00
Jon Gjengset cf06621998 tokio-sync: Add async mutual exclusion primitive (#964)
This PR introduces `Lock`: A concurrency primitive built on top of `Semaphore` that provides a `Mutex`-like primitive that interacts nicely with futures. Specifically, `LockGuard` (in contrast to `MutexGuard`) does _not_ borrow the `Lock`, and can thus be passed into a future where it will later be unlocked.

This replaces #958, which attempted to introduce a less generic version. The primitive proposed there will instead live in [`async-lease`](https://github.com/jonhoo/async-lease).
2019-04-18 13:16:26 -04:00
Lucio Franco 7e51ab05e9 buf: Add IntoStream (#1048)
* buf: Add IntoStream

* Add debug implementation for IntoStream

* Add get_ref, get_mut and into_inner
2019-04-18 11:42:34 -04:00
Eliza Weisman 4bfa4ffcdf trace-core: Dispatchers unset themselves (#1033)
This branch changes `dispatcher::get_default` to unset the thread's
current dispatcher while the reference to it is held by the closure.
This prevents infinite loops if the subscriber calls code paths which
emit events or construct spans. 

Note that this also means that nested calls to `get_default` inside of a
`get_default` closure will receive a `None` dispatcher rather than the
"actual" dispatcher. However, it was necessary to unset the default in
`get_default` rather than in dispatch methods such as `Dispatch::enter`,
as when those functions are called, the current state has already been
borrowed.

Before:
```
test enter_span              ... bench:           3 ns/iter (+/- 0)
test span_no_fields          ... bench:          51 ns/iter (+/- 12)
test span_repeatedly         ... bench:       5,073 ns/iter (+/- 1,528)
test span_with_fields        ... bench:          56 ns/iter (+/- 49)
test span_with_fields_record ... bench:         363 ns/iter (+/- 61)
```

After:
```
test enter_span              ... bench:           3 ns/iter (+/- 0)
test span_no_fields          ... bench:          35 ns/iter (+/- 12)
test span_repeatedly         ... bench:       4,165 ns/iter (+/- 298)
test span_with_fields        ... bench:          48 ns/iter (+/- 12)
test span_with_fields_record ... bench:         363 ns/iter (+/- 91)
```

Closes #1032 

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-16 15:51:45 -07:00
Taiki Endo 88b942652c async-await: fix examples (#1050)
* Fix crate path in `Cargo.toml` of examples
* Add `edition2018` to examples in the documentation to make it compiled
  on Rust 2018
* Fix an example in the documentation
2019-04-16 14:19:38 -04:00
Taiki Endo 5029e80a89 async-await: update to new futures_api (#1049) 2019-04-16 14:07:03 -04:00
Eliza Weismanandcsmoe 847fb59b17 trace-core: Introduce callsite classification in metadata (#1046)
## Motivation

To ease the implementation of `Subscriber::register_callsite`, a field
should be added to `Metadata` to indicate if this callsite is an event or
a span.

## Solution

A new struct, `Kind`, is added to the `metadata` module in
`tokio-trace-core`, and a `Kind` field is added to the `Metadata`
struct. Macros which construct `metadata` now require a `Kind`.

`Kind` is represented as a struct with a private inner enum to allow new
`Kind`s to be added without breaking changes. However, the _addition_ of
the kind field _is_ a breaking change. While this could be done in a
backward-compatible way, it would permit the construction of metadata
with unknown kinds, and since the next `tokio-trace-core` release will
be a breaking change, I opted to make the breaking change instead.

New API tests for the `callsite!` and `metadata!` macros have been added
to guard against future API breakage.

Fixes: #986
Closes: #1008

Co-Authored-By: csmoe <[email protected]>
2019-04-11 11:56:42 -07:00
Jane Lusby b4fe517a16 trace-core: add a function to rebuild cached interest (#1039)
## Motivation

Currently, `tokio-trace-core` permits `Subscriber`s to indicate that
they are "always", "sometimes", or "never" interested in a particular
callsite. When "always" or "never" is returned, then the interest is
cached and the subscriber will not be asked again about that callsite.
This is much more efficient than requiring the filter to be re-evaluated
every time the callsite is hit.

However, if a subscriber wishes to change its filter configuration
dynamically at runtime, it cannot benefit from this caching. Instead, it
must always return `Interest::sometimes`.  Even when filters change very
infrequently, they must still always be re-evaluated every time.

In order to support a use-case where subscribers may change their filter
configuration at runtime (e.g. tokio-rs/tokio-trace-nursery#42),
but do so infrequently, we should introducing a new function to
invalidate the cached interest.

## Solution

This branch adds a new function in the `callsite` module, called
`rebuild_interest_cache`, that will invalidate and rebuild all cached
interest.

## Breaking Change

In order to fix a race condition that could occur when rebuilding
interest caches using `clear_interest` and `add_interest`, these methods
have been replaced by a new `set_interest` method. `set_interest` should
have the semantics of atomically replacing the previous cached interest,
so that the callsite does not enter a temporary state where it has no
interest.

Closes #1038

Co-Authored-By: yaahallo <[email protected]>
2019-04-10 13:51:05 -07:00
Simon Wollwage 7ae010f0f3 async-await: Use Context instead of Waker in poll (#1041)
Rust nightly std::future::Future recently changed Waker
to Context.

Change to use Context

Co-Authored-By: Kintaro <[email protected]>
2019-04-10 09:14:31 -07:00
Carl Lerche 9144b2ff53 sync: remove unnecessary imports (#1043) 2019-04-09 12:26:11 -07:00
Lev Eniseev 2c4549a18a Add example of blocking environment (#1036) 2019-04-09 12:10:15 -07:00
João Oliveira 4f819b7cd1 trace: fix counters example, Span IDs must be greater than zero (#1037)
## Motivation
tokio-trace counter example was panicking due to returning 0 as the first Span Id

## Solution
start ID's with 1 instead
2019-04-05 13:51:20 -07:00
Eliza Weisman 197f88f3bc trace: Change Span::enter and record to take &self (#1029)
## Motivation

The `Span::enter` function previously required an `&mut` reference to
enter a span. This is a relic of an earlier design where span closure
logic was determined by dropping an inner span component, and is no
longer strictly necessary.

Requiring `&mut self` to enter a span leads to awkward patterns in cases
when a user wishes to enter a span and then call methods on the span
(such as recording field values). For example, we cannot say
```rust
let mut span = span!("foo", bar);
span.enter(|| {
    span.record("bar" &false);
});
```
since the span is mutably borrowed by `enter`. Instead, we must clone
the span, like so:
```rust
let mut span = span!("foo", bar);
span.clone().enter(|| {
    span.record("bar" &false);
});
```

Having to clone the span is somewhat less ergonomic, and it has
performance disadvantages as well: cloning a `Span` will clone the
span's `Dispatch` handle, requiring an `Arc` bump, as well as calling
the `Subscriber`'s `clone_span` and `drop_span` functions. If we can
enter spans without a mutable borrow, we don't have to update any of
these ref counts.

The other reason we may wish to require mutable borrows to enter a span
is if we want to disallow entering a span multiple times before exiting
it. However, it is trivially possible to re-enter a span on the same
thread regardless, by cloning the span and entering it twice. Besides,
there may be a valuable semantic meaning in entering a span from inside
itself, such as when a function is called recursively, so disallowing
this is not a goal.

## Solution

This branch rewrites the `Span::enter`, `Span::record`, and
`Span::record_all` functions to no longer require mutable borrows. 

In the case of `record` and `record_all`, this was trivial, as borrowing
mutably was not actually *necessary* for those functions. For `enter`,
the `Entered` guard type was reworked to consist of an `&'a Inner`
rather than an `Inner`, so it is no longer necessary to `take` the
span's `Inner`. 

## Notes

In addition to allowing spans to be entered without mutable borrows,
`Entered` was changed to exit the span automatically when the guard is
dropped, so we may now observe correct span exits even when unwinding.

Furthermore, this allows us to simplify the `enter` function a bit,
leading to a minor performance improvement when entering spans.

Before:
```
test enter_span              ... bench:          13 ns/iter (+/- 1)
```

...and after:
```
test enter_span              ... bench:           3 ns/iter (+/- 1)
```

Note that this branch also contains a change to make the
`subscriber::enter_span` benchmark more accurate. Previously, this
benchmark constructed a new span inside of `b.iter(|| {...})`. This
means that the benchmark was measuring not only the time taken to enter
a span, but the time taken to construct a `Span` handle as well.
However, we already have benchmarks for span construction, and the
intention of this particular benchmark was to measure the overhead of
constructing a span.

I've updated the benchmark by moving the span construction out of the
`iter` closure. Now, the span is constructed a single time and entered
on every iteration. This allows us to measure only the overhead of
actually entering a span. The "before" benchmark numbers above were
recorded after backporting this change to master, so they are "fair" to
the previous implementation. Prior to this change the benchmark took
approximately 53 ns.

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-03 15:06:47 -07:00
Eliza Weisman 44f65afcc6 trace: Allow field names to be separated by .s (#1027)
## Motivation

In order to support conventions that add namespacing to `tokio-trace`
field names, it's necessary to accept at least one type of separator
character. Currently, the `tokio-trace` macros only accept valid Rust
identifiers, so there is no clear separator character for namespaced
conventions. See also #1018.

## Solution

This branch changes the single `ident` fragment matcher for field names
to match *one or more* `ident` fragments separated by `.` characters.

## Notes

The resulting key is still exposed to `tokio-trace-core` as a string
constant created by stringifying the dotted expression. However, if
`tokio-trace-core` were later to adopt a first class notion of
hierarchical field keys, we would be able to track that change in
`tokio-trace` as an implementation detail.

Closes #1018.
Closes #1022.

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-03 14:44:11 -07:00
Eliza Weisman 4271a9cd8d trace: Fix subscriber benchmarks panicking (#1028)
This branch fixes the `tokio-trace` Subscriber benchmarks panicking due
to constructing spans with ID 0. They will now use an arbitrary constant
instead.

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-02 13:42:31 -07:00
Matthias Prechtl 9d8096b911 Improve documentation of Subscriber::record and Subscriber::event (#1026) 2019-04-02 12:44:01 -07:00
João Oliveira 597f271c08 trace: Remove default trace level and make levels mandatory on span! macro (#1025)
## Motivation 

Was determined that having the span! macro default to the TRACE level is
probably not ideal (see discussion on #952). 

Closes #1013

## Solution 

Remove default trace level and make log lvl mandatory on span! macro,
and add the respective `trace_span!`, `debug_span!`, `info_span!`,
`warn_span!` and `error_span!` macros that behave as span! macro, but
with defined log levels

## Notes 

I think this is it, also removed some captures that were repeated, and
some testcases that also seemed repeated after adding the mandatory log
level, but please review it, if more tests or examples are needed happy
to provide (tried to find a way to get the generated macros log level,
but didn't find one, if there is a way i can add tests to assert that
the generated macro has the matching log level ). thanks
2019-04-02 11:29:23 -07:00
Taiki Endo 599955f716 Replace try! macro with ? operator (#1024) 2019-04-01 13:45:59 -07:00
Ivan Petkov 91bb0f73f5 signal: refactor Windows registrations to be lazy (#1001)
- Use `Handle::default` over `Handle::current` for consistent semantics
- Make all `windows::Event` constructors lazily invoke `global_init`
  so they can be safely constructed off-task
- Don't assume the reactor is alive and event registration will be done
  when calling `global_init`

Add windows regression tests. Unfortunately, Windows doesn't have a
reliable way of programmatically sending CTRL_C or CTRL_BREAK events
to a progress, so the tests can only exercise our internal machinery by
invoking the handler that we register with the OS

Fixes #999
2019-04-01 12:46:22 -07:00
Eliza Weisman 6c9d8abba9 trace: Make Span API functions taking IDs a little more flexible (#1021)
This branch modifies the `tokio_trace::Span` API functions that take
span IDs (the `Span::child_of` constructor, and the `Span::follows_from`
method) so that more types bearing a span ID can be passed as an
argument. Span IDs may now be passed directly without requiring them to
be passed as `Some(id)`. This should make the API slightly more
ergonomic.

Also, it changes the `Span::field` method to take an `AsField` rather
than a `Borrow<str>`.

Signed-off-by: Eliza Weisman <[email protected]>
2019-04-01 11:42:29 -07:00
Carl Lerche 824b7b6759 buf: stream and iter helpers (#1011) 2019-03-29 12:26:13 -07:00
Carl Lerche cb91dd274a buf: impl Error for CollectVecError (#1010) 2019-03-29 08:49:08 -07:00
Eliza Weisman ea7178b8c6 trace-core: Add slightly more useful debug impls (#1014)
This branch improves the `fmt::Debug` implementation for `Metadata`,
and adds `fmt::Display` implementations for `FieldSet` and `ValueSet`.

When formatting a `Metadata`, only present fields are formatted --- if
optional fields, such as the file, line number, and module path are
`None`, they will be excluded. In addition, `Metadata` now formats its
`FieldSet` using `FieldSet`'s `fmt::Display` implementation, which is a
bit less noisy. Finally, the `Debug` output for `Metadata` now includes
the callsite that the metadata originates from.

The intention behind these changes is to make the output from failed
tests somewhat easier to interpret.

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-28 14:47:06 -07:00
Carl Lerche a99b8e2e0b buf: impl size_hint for str types + reorg tests (#1012) 2019-03-28 14:02:45 -07:00
Carl Lerche 03859a7dcd buf: implement FromBufStream for Bytes (#1009) 2019-03-27 19:22:06 -07:00
Eliza Weisman d8177f81ac trace: Allow trace instrumentation to emit log records (#992)
## Motivation

`tokio-trace` currently offers a strategy for compatibility with the
`log` crate: its macros can be dropped in as a replacement for `log`'s
macros, and a subscriber can be used that translates trace events to log
records. However, this requires the application to be aware of
`tokio-trace` and manually set up this subscriber.

Many libraries currently emit `log` records, and would like to be able
to emit `tokio-trace` instrumentation instead. The `tokio` runtimes are
one such example. However, with the current log compatibility strategy,
replacing existing logging with trace instrumentation would break
`tokio`'s logs for any downstream user which is using only `log` and not
`tokio-trace`. It is desirable for libraries to have the option to emit
both `log` _and_ `tokio-trace` diagnostics from the same instrumentation
points.

## Solution

This branch adds a `log` feature flag to the `tokio-trace` crate, which
when set, causes `tokio-trace` instrumentation to emit log records as well
as `tokio-trace` instrumentation. 

## Notes

In order to allow spans to log their names when they are entered and 
exited even when the span is disabled, this branch adds an 
`&'static Metadata` to the `Span` type. This was previously stored in
the `Inner` type and was thus only present when the span was enabled.
This makes disabled spans one word longer, but enabled spans remain
the same size.

Fixes: #949

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-26 16:43:05 -07:00
Son ceca2a3cd6 chore: add license to tokio (#1006) 2019-03-26 08:41:41 -07:00
Son 1524ee4b60 trace: Add static level filtering (#987)
## Motivation

`tokio-trace` should have static verbosity level filtering, like the
`log` crate. The static max verbosity level should be controlled at
compile time with a set of features. It should be possible to set a
separate max level for release and debug mode builds.

## Solution

We can do this fairly similarly to how the `log` crate does it:
`tokio-trace` should export a constant whose value is set based on the
static max level feature flags. Then, we add an if statement to the
`span!` and `event!` macros which tests if that event or span's level
is enabled.

Closes #959
2019-03-25 15:19:20 -07:00
MOZGIII 7793d63739 Corrected doc for tokio_buf SizeHint (#1003) 2019-03-25 16:54:49 -04:00
Red Hara e0e26bc223 Fix typo in README.md in examples (#1002) 2019-03-24 13:02:11 -04:00
Eliza Weisman 9c5cad037f trace-core: Add overrideable downcasting to Subscribers (#974)
## Motivation

In order to implement "out of band" `Subscriber` APIs in third-party
subscriber implementations (see [this comment]) users may want to 
downcast the current `Dispatch` to a concrete subscriber type.

For example, in a library for integrating `tokio-trace` with a fancy new
(hypothetical) distributed tracing technology "ElizaTracing", which uses
256-bit span IDs, we might expect to see a function like this:
```rust

pub fn correlate(tt: tokio_trace::span::Id, et: elizatracing::SpanId) {
    tokio_trace::dispatcher::with(|c| {
        if let Some(s) = c.downcast_ref::<elizatracing::Subscriber>() {
            s.do_elizatracing_correlation_magic(tt, et);
        }
    }); 
}
```

This allows users to correlate `tokio-trace` IDs with IDs in the
distributed tracing system without having to pass a special handle to
the subscriber through application code (as one is already present in
thread-local storage, but with its type erased).

## Solution

This branch makes the following changes:
 * Add an object-safe `downcast_raw` method to the `Subscriber` trait,
   taking a `TypeId` and returning an `*const ()` if the type ID 
   matches the subscriber's type ID, or `None` if it does not, and
 * Add `is<T>` and `downcast_ref<T>` functions to `Subscriber` 
   and `Dispatch`, using `downcast_raw`.

Unlike the approach implemented in #950, the `downcast_raw` method is
object-safe, since it takes a `TypeId` rather than a type _parameter_ 
and returns a void pointer rather than an `&T`. This means that
`Subscriber` implementations can override this method if necessary. For
example, a `Subscriber` that fans out to multiple component subscribers
can downcast to their component parts, and "chained" or "middleware"
subscribers, which wrap an inner `Subscriber` and modify its behaviour 
somehow, can downcast to the inner type if they choose to.

[this comment]: https://github.com/tokio-rs/tokio/issues/932#issuecomment-469473501
[`std::error::Error`'s]: https://doc.rust-lang.org/1.33.0/src/std/error.rs.html#204

Refs: #950, #953, https://github.com/tokio-rs/tokio/issues/948#issuecomment-469444293

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-22 16:21:46 -07:00
Eliza Weisman 30330da11a chore: Fix examples not working with cargo run (#998)
* chore: Fix examples not working with `cargo run`

## Motivation

PR #991 moved the `tokio` crate to its own subdirectory, but did not
move the `examples` directory into `tokio/examples`. While attempting to
use the examples for testing another change, I noticed that #991 had
broken the ability to use `cargo run`, as the examples were no longer
considered part of a crate that cargo was aware of:

```
tokio on master [$] via 🦀v1.33.0 at ☸️ aks-eliza-dev
➜  cargo run --example chat
error: no example target named `chat`

Did you mean `echo`?
```

## Solution

This branch moves the examples into the `tokio` directory, so cargo is
now once again aware of them:

```
tokio on eliza/fix-examples [$] via 🦀v1.33.0 at ☸️ aks-eliza-dev
➜  cargo run --example chat
   Compiling tokio-executor v0.1.7 (/Users/eliza/Code/tokio/tokio-executor)
   Compiling tokio-reactor v0.1.9
   Compiling tokio-threadpool v0.1.13
   Compiling tokio-current-thread v0.1.6
   Compiling tokio-timer v0.2.10
   Compiling tokio-uds v0.2.5
   Compiling tokio-udp v0.1.3
   Compiling tokio-tcp v0.1.3
   Compiling tokio-fs v0.1.6
   Compiling tokio v0.1.18 (/Users/eliza/Code/tokio/tokio)
    Finished dev [unoptimized + debuginfo] target(s) in 7.04s
     Running `target/debug/examples/chat`
server running on localhost:6142
```

Signed-off-by: Eliza Weisman <[email protected]>

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-22 15:25:42 -07:00
Carl Lerche 6e4945025c chore: fix Cargo.toml files 2019-03-22 14:10:06 -07:00
Carl Lerche 3c8f110730 Bump Tokio version to v0.1.18 (#997)
Also bumps:

- tokio-signal (0.2.8)
- tokio-current-thread (0.1.6)
- tokio-executor (0.1.7)
- tokio-threadpool (0.1.13)

[ci-release]
2019-03-22 13:55:48 -07:00
Carl Lerche 678f15bd48 ci: skip crates.io dep run when releasing (#995)
#993 introduces changes in a sub crate that other Tokio crates depend
on. To make CI pass, a `[patch]` statement and `path` dependencies are
used.

When releasing, these must be removed. However, the commit that
removes them and prepares the crates for release will not be able to
pass CI.

This commit adds a conditional on a special `[ci-release]` snippet in
the commit message. If this exists, CI is only run with the full "patched"
dependencies.
2019-03-22 11:58:00 -07:00
Carl Lerche b1172f8074 executor: add TypedExecutor (#993)
Adds a `TypedExecutor` trait that describes how to spawn futures of a specific
type. This is useful for implementing functions that are generic over an executor
and wish to support both `Send` and `!Send` cases.
2019-03-21 14:30:18 -07:00
Carl Lerche cdde2e7a27 chore: repo maintenance + no path dependencies (#991)
- Move `tokio` into its own directory.
- Remove `path` dependencies.
- Run tests with once with crates.io dep and once with patched dep.
2019-03-19 14:58:59 -07:00
Eliza Weisman 85487727d4 trace: Span API polish (#988)
This branch makes the following changes to `tokio-trace`'s `Span` type:

* **Remove manual close API from spans**
  In practice, there wasn't really a use-case for this, and it 
  complicates the implementation a bit. We can always add it back later.

* **Remove generic lifetime from `Span`**
  Again, there wasn't actually a use-case for spans with metadata that
  doesn't live for the static lifetime, and it made using `Span`s in 
  other types somewhat inconvenient. It's also possible to implement an
  alternative API for non-static spans on top of the `tokio-trace-core`
  primitives.

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-18 12:44:46 -07:00
Lucio Franco 92d51202ef trace: Remove git dep on trace core for crates version (#984) 2019-03-13 15:07:47 -04:00
Lucio Franco cb55bf4012 signal: Fix deprecated use of Handle::current (#981) 2019-03-13 11:56:25 -07:00
Carl Lerche 987ccfc8ac Bump Tokio to v0.1.17 (#983)
Also bumps:
- tokio-sync (v0.1.4)
2019-03-13 11:19:22 -07:00
Sean McArthur 1bc6d75543 sync: add mpsc benchmarks of small, medium, and large message types (#982) 2019-03-13 11:00:42 -07:00
Sean McArthur 27148d6110 sync: free chan Blocks when Chan is dropped (#978) 2019-03-13 10:38:14 -07:00
Carl Lerche a1871b1480 Prepare tokio-trace-core for initial release. (#979) 2019-03-13 10:29:27 -07:00
Eliza Weisman acd08eb23d tokio: Enable trace subscriber propagation in the runtime (#966)
Signed-off-by: Eliza Weisman <[email protected]>
2019-03-13 10:28:45 -07:00
南浦月 90b1a01010 tokio: fix dependency versions (#944)
#943
2019-03-13 07:47:05 -07:00
Thomas Lacroix 676824988e sync: impl Error for oneshot and watch error types (#967)
Refs: #937
2019-03-12 08:51:23 -07:00
Eliza Weisman 46149f031e trace-core: Fix NoSubscriber causing panics (#975)
PR #973 changed the `tokio_trace_core::span::Id::from_u64` function to
require that the provided `u64` be greater than zero. However, I had
forgotten that the implementation of `Subscriber` for the `NoSubscriber`
type (which is used when no default subscriber is set) always returned
`span::Id::from_u64(0)` from its `new_span` method. In combination with
the assert added in #973, this means that every time a span is hit when
no subscriber is set, `tokio-trace-core` will panic.

This branch fixes the panics by having `NoSubscriber` construct span IDs
using a different (arbitrarily chosen) non-zero constant.

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-11 17:08:04 -07:00
Eliza Weisman 5510ba6dba trace-core: Require span IDs to be > 0 (#973)
This branch changes `tokio_trace_core::span::Id::from_u64` to assert
that the integer from which the span ID is constructed is greater than
zero. This is to enable future use of non-zero optimization.

Unfortunately, we can't actually use a `NonZeroU64` _now_, as that type
was only stabilized in Rust 1.28.0, and `tokio`'s current minimum
supported Rust version is 1.26.0.

Adding and documenting the assertion now allows us to change the
internal representation to `NonZeroU64` later (when 1.28.0 is the
minimum supported Rust version), without causing a breaking change.

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-11 16:18:40 -07:00
Eliza Weisman b8f63308d7 trace-core: Pass dispatcher by ref to dispatcher::with_default (#971)
* trace-core: Pass dispatcher by ref to `dispatcher::with_default`

As requested by @carllerche in https://github.com/tokio-rs/tokio/pull/966#discussion_r264380005, this branch changes the
`dispatcher::with_default` function in `tokio-trace-core` to take the
dispatcher by ref and perform the clone internally. This makes this
function more consistant with other `with_default` functions in other
crates.

Signed-off-by: Eliza Weisman <[email protected]>

* trace: Don't set the default dispatcher on entering a span

Setting the default dispatcher on span entry is a relic of when spans
tracked their parent's ID. At that time, it was necessary to ensure that
any spans created inside a span were observed by the same subscriber
that originally provided the entered span with an ID, as otherwise, new
spans would be created with parent IDs that did not originate from that
subscriber.

Now that spans don't track their parent ID, this is no longer necessary.
However, removing this behavior does mean that if a span is entered
outside of the subscriber context it was created in, any subsequent
spans will be observed by the current default subscriber and thus will
not be part of the original span's trace tree. Since subscribers are not
expected to change frequently, and spans are not expected to move
between them, this is likely acceptable.

I've removed the tests for the old behavior.

Note that this change improves the performance of span entry/exit fairly
significantly. Here are the results of running a benchmark that enters
a span, does nothing, and immediately exits it, before this change:

```
test enter_span              ... bench:          93 ns/iter (+/- 14)
```

...and after:

```
test enter_span              ... bench:          51 ns/iter (+/- 9)
```

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-11 15:29:00 -07:00
Eliza Weisman 4313d65b38 trace: Switch to using local_inner_macros for instrumentation API (#969)
## Motivation

Currently, it isn't possible to import individual macros from
`tokio-trace` using the macros 1.2 syntax:

```rust
use tokio_trace::{debug, info, span};
```

This is because these macros require that `callsite` and `enabled` are
imported as well.

## Solution

This branch resolves the problem by adding the [`local_inner_macros`]
attribute to the instrumentation API's macros. This allows other macros
from within the crate to be used without requiring them to be explicitly
imported. 

However, this also requires duplicating any macros from other sources
(such as std and `tokio-trace-core`) with wrappers due to the behaviour
of `local_inner_macros`. I've added these wrapper macros as well.

Since the macros got even longer as a result of this, I've moved them
to a separate file to make `lib.rs` easier to read. I've also wrapped
some very long lines in the macros, and removed the explicit drop of
the result of evaluating some event macros (it's no longer necessary
as all event macros now evaluate to `()`).

[`local_inner_macros`]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/macros/macro-changes.html#local-helper-macros

Fixes #968

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-11 14:48:23 -07:00
Eliza Weisman e780fccce4 trace: Minor documentation improvements (#963) 2019-03-07 21:36:15 -08:00
Eliza Weisman b01e71b3d8 trace-core: API polish (#962)
This branch makes a handful of `tokio-trace-core` API improvements, mostly
around naming. In particular:

 * Rename `dispatcher::with` to `dispatcher::get_default`
 * Rename `Event::observe` to `Event::dispatch`
 * Make `field::ValidLen` trait private

Closes #948
Closes #960

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-07 15:19:26 -08:00
Eliza Weisman 7f911b6b70 trace-core: Debreak RustDoc links (#961)
This commit fixes a bunch of broken links in the `tokio-trace-core` API
docs.

Refs: #957
2019-03-07 14:42:08 -08:00
Eliza Weisman d88aba8d1c trace: Add arguments struct to subscriber::Record (#955)
This branch changes the `Subscriber::record` method to take a new
arguments struct, `span::Record`. The `field::Record` trait was renamed
to `field::Visit` to prevent name conflicts.

In addition, the `ValueSet::is_empty`, `ValueSet::contains`, and
`ValueSet::record` methods were made crate-private, as they are exposed
on the `Attributes` and `Record` types. 

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-07 12:41:10 -08:00
Eliza Weisman 6fbef0a528 trace-core: Add 'static bound to Subscriber (#953) 2019-03-07 11:54:21 -08:00
Blake Smith 9be5f3f9ff Fix TcpStream::try_clone error message (#946) 2019-03-04 14:17:08 -08:00
Carl Lerche e28856cffe Bump Tokio to 0.1.16. (#941)
Also bumps:

* tokio-current-thread (0.1.5)
* tokio-fs (0.1.6)
* tokio-io (0.1.12)
* tokio-reactor (0.1.9)
* tokio-threadpool (0.1.12)
2019-03-01 21:04:43 -08:00
Carl Lerche 85e3bd34af async-await: fix build for latest nightly (#940)
Fixes: #936
2019-03-01 15:40:42 -08:00
Lucio Franco db4019d84a trace: Fix tokio-trace documentation url in the README (#939) 2019-03-01 15:31:59 -08:00
Carl Lerche 195c4b0496 Bump tokio-sync version to v0.1.3 (#938) 2019-03-01 12:57:07 -08:00
Carl Lerche 619d3b163b sync: impl Error for mpsc error types (#937) 2019-03-01 12:24:17 -08:00
Eliza Weisman 5ff6e37c59 trace: Allow specifying a new span's parent (#923)
This branch allows users of `tokio-trace` to explicitly set a span's
parent, or indicate that a span should be a new root of its own trace
tree. A `parent: ` key has been added to the `span!` macros. When a span
is provided, that span will be set as the parent, while `parent: None`
will result in a new root span. No `parent:` key results in the current
behaviour.

A new type, `span::Attributes`, was added to `tokio-trace-core` to act
as an arguments struct for the `Subscriber::new_span` method. This will
allow future fields to be added without causing breaking API changes.
The `Attributes` struct currently contains the new span's metadata,
`ValueSet`, and parent.

Finally, the `span::Span` type in `-core` was renamed to `span::Id`, for
consistency with `tokio-trace` and to differentiate it from
`span::Attributes`. This name was chosen primarily due to precedent in
other tracing systems.

Closes #920 

Signed-off-by: Eliza Weisman <[email protected]>
2019-03-01 11:29:11 -08:00
Carl Lerche 43d69d77e2 Set up CI with Azure Pipelines (#926)
Use Azure Pipelines for CI. This migrates away from Travis and
Appveyor.
2019-03-01 09:12:21 -08:00
Carl Lerche dbb04e310c Fix rustfmt check (#927)
* Add set -e to .travis.yml
* Fix fmt
* Fix codec feature
2019-02-24 15:41:26 -08:00
Carl Lerche 0e2e07812a Bump tokio-buf to v0.1.0 (#925) 2019-02-23 21:58:47 -08:00
Carl Lerche 047d0b821c buf: misc polish (#924)
- Rename feature flag `util`.
- Rename module `util`
- Move `error` module into `util`.
- Move `BufStream` impls into dedicated file.
2019-02-23 10:17:21 -08:00
Carl Lerche 70f4fc481c sync: Add watch, a single value broadcast channel (#922)
A single-producer, multi-consumer channel that only retains the _last_ sent
value. Values are broadcasted out.

This channel is useful for watching for changes to a value from multiple
points in the code base (for example, changes to a configuration value).
2019-02-22 21:54:50 -08:00
Carl Lerche 7039f02bb2 Bump tokio-async-await to 0.1.6 (#921) 2019-02-22 17:15:42 -08:00
Taiki Endo 4985e0c608 async-await: update to new future/task API (#919)
- Rewrite noop_waker with items from the new API and replaces
  LocalWaker with Waker.

- Bump the minimum required version for `tokio-async-await` to
  1.34.0-nightly.

- `Unpin` was added to std prelude.

- Add `cargo check` to .travis.yml

Fixes: #908
2019-02-22 13:30:21 -08:00
Toralf Wittner fd22090df8 tokio-io: Add unsplit. (#807)
Provide a way to restore an I/O object from its `ReadHalf` and
`WriteHalf`.

Closes #803

Co-Authored-By: twittner <[email protected]>
2019-02-22 12:23:36 -08:00
Eliza Weisman 02a5091885 trace: Minor doc improvements (#913)
This branch adds links to the master RustDoc published by CI to the
`tokio-trace` and `tokio-trace-core` README. In addition, it fixes a
broken links in the RustDoc for `tokio-trace` and updates the
`tokio-trace-core` RustDoc to match the README.

Signed-off-by: Eliza Weisman <[email protected]>
2019-02-22 11:07:53 -08:00
Carl Lerche 80162306e7 chore: apply rustfmt to all crates (#917) 2019-02-21 11:56:15 -08:00
Nicholas Young ab595d0825 threadpool: fix typo in documentation (#915) 2019-02-21 09:28:44 -08:00
Carl Lerche 41a2245b85 chore: remove patch statements in Cargo.toml (#914) 2019-02-21 09:28:14 -08:00
Carl Lerche 7ca4f3ec4b Bump tokio-sync to v0.1.2. (#909) 2019-02-21 09:28:05 -08:00
Carl Lerche 0da649727c fs: fix tests (#916) 2019-02-20 21:56:23 -08:00
Linus Färnstrand 1cf5f73651 Read write helpers (#896)
Provides async versions of read / write helpers being stabilized in `std`.
2019-02-20 14:38:49 -08:00
Sean McArthur beb639a030 sync: fix warnings in benches and tests (#912) 2019-02-20 14:07:53 -08:00
Kevin Leimkuhler 75ab7c9e9b trace: Allow Span IDs to be converted back to u64s (#910)
## Motivation

As described in #905, subscribers have no way to get the numeric value of a span ID back _out_ of a `Span`.  

## Solution

Add a `Span::into_u64` method that returns the inner `u64` span ID

Closes #905

Signed-off-by: kleimkuhler <[email protected]>
2019-02-20 13:26:20 -08:00
David Wilemski cec9efeb7a Fix summary of tokio::util::StreamExt (#861)
The `throttle` function was not mentioned in the summary block but is listed as a method for the trait.
2019-02-20 13:24:48 -08:00
Sean McArthur f9345f99bb sync: drop old tasks in oneshot (#911) 2019-02-20 12:50:29 -08:00
Kevin M Granger ab206b976c fs: add CloneFuture for File::try_clone (#850) 2019-02-20 12:25:50 -08:00
Carl Lerche 3d787b16c7 sync: add loom test for mpsc (#903)
This patch updates tokio_sync::mpsc to support using loom for fuzz
testing. It includes a basic fuzz test.
2019-02-20 10:05:56 -08:00
Paul Osborne f513558076 tokio-reactor: impl AsRawFd for reactor for unix (#890)
In order to support nesting a tokio reactor within another event
system exposing the file descriptor for the underlying reactor
is useful and is already implemented for mio::Poll.

Signed-off-by: Paul Osborne <[email protected]>
2019-02-19 20:23:19 -08:00
Sean McArthur d0cdcff8aa sync: improve assert message for bounded channel buffer size 2019-02-19 17:09:36 -08:00
Carl Lerche e3115231dd sync: fix mpsc/sempahore when releasing permits (#904)
This patch fixes Semaphore by adding a missing code path to the release
routine that handles the case where the waiter's node is queued in the
sempahore but has not yet been assigned the permit.

This fix is used by mpsc to handle the case when the Sender has called
`poll_ready` and is dropped before the permit is acquired.

Fixes #900
2019-02-19 16:26:05 -08:00
Andy Russell 2d5aa82341 chore: move doc comments inside macro invocations (#901) 2019-02-19 13:54:52 -08:00
Lucio Franco dd66096ea0 buf: Add BufStreamExt trait and add a core feature (#897)
This change adds an extension trait to `BufStream` and puts the core
trait behind a feature flag for optional use.

This mainly adds the additional functions in an extension trait to
allow the user to select if they want just the core trait or the fully
featured version. Now the user can add the core feature to _not_
include the extension trait. By deafult, this feature is disabled.
2019-02-19 13:30:37 -08:00
Eliza Weisman c08e73c8d4 Introduce tokio-trace (#827)
<!-- Thank you for your Pull Request. Please provide a description above
and review the requirements below.

Bug fixes and new features should include tests.

Contributors guide:
https://github.com/tokio-rs/tokio/blob/master/CONTRIBUTING.md -->

## Motivation

In asynchronous systems like Tokio, interpreting traditional log
messages can often be quite challenging. Since individual tasks are
multiplexed on the same thread, associated events and log lines are
intermixed making it difficult to trace the logic flow. Currently, none
of the available logging frameworks or libraries in Rust offer the
ability to trace logical paths through a futures-based program.

There also are complementary goals that can be accomplished with such a
system. For example, metrics / instrumentation can be tracked by
observing emitted events, or trace data can be exported to a distributed
tracing or event processing system.

In addition, it can often be useful to generate this diagnostic data in
a structured manner that can be consumed programmatically. While prior
art for structured logging in Rust exists, it is not currently
standardized, and is not "Tokio-friendly".

## Solution

This branch adds a new library to the tokio project, `tokio-trace`.
`tokio-trace` expands upon logging-style diagnostics by allowing
libraries and applications to record structured events with additional
information about *temporality* and *causality* --- unlike a log
message, a span in `tokio-trace` has a beginning and end time, may be
entered and exited by the flow of execution, and may exist within a
nested tree of similar spans. In addition, `tokio-trace` spans are
*structured*, with the ability to record typed data as well as textual
messages.

The `tokio-trace-core` crate contains the core primitives for this
system, which are expected to remain stable, while `tokio-trace` crate
provides a more "batteries-included" API. In particular, it provides
macros which are a superset of the `log` crate's `error!`, `warn!`,
`info!`, `debug!`, and `trace!` macros, allowing users to begin the
process of adopting `tokio-trace` by performing a drop-in replacement.

## Notes

Work on this project had previously been carried out in the
[tokio-trace-prototype] repository. In addition to the `tokio-trace` and
`tokio-trace-core` crates, the `tokio-trace-prototype` repo also
contains prototypes or sketches of adapter, compatibility, and utility
crates which provide useful functionality for `tokio-trace`, but these
crates are not yet ready for a release. When this branch is merged, that
repository will be archived, and the remaining unstable crates will be
moved to a new `tokio-trace-nursery` repository. Remaining issues on the
`tokio-trace-prototype` repo will be moved to the appropriate new repo.

The crates added in this branch are not _identical_ to the current head
of the `tokio-trace-prototype` repo, as I did some final clean-up and docs
polish in this branch prior to merging this PR.

[tokio-trace-prototype]: https://github.com/hawkw/tokio-trace-prototype

Closes: #561

Signed-off-by: Eliza Weisman <[email protected]>
2019-02-19 12:15:01 -08:00
Sean McArthur d1d72dc1c8 reactor: use AtomicTask::register to reduce unnecessary task clones (#899) 2019-02-18 13:04:07 -08:00
Sean McArthur 27a42b980c reactor: release write lock before register syscall 2019-02-14 16:11:05 -08:00
Sean McArthur 7a50e09495 reactor: replace AtomicTask with that from tokio-sync 2019-02-14 16:10:48 -08:00
Sean McArthur d7a556fe8b sync: add AtomicTask::take_task() 2019-02-14 16:10:48 -08:00
Sean McArthur 860ca79d62 Check Task::will_notify_current before cloning in AtomicTask 2019-02-14 13:26:53 -08:00
Sean McArthur 7b98bf7da3 Use tokio-sync's AtomicTask in mpsc 2019-02-14 13:26:53 -08:00
Sean McArthur 49774f6af1 Add poll_ready and constructor benchmarks for tokio-sync 2019-02-14 13:26:53 -08:00
Yilin Chen ec22fb9843 reactor: replace ATOMIC_USIZE_INIT with AtomicUsize::new(0) (#889)
ATOMIC_BOOL_INIT is deprecated since 1.34 because the const fn
AtomicUsize::new is now preferred. As deny(warnings) is set,
tokio fails to build on latest nightly. This will fix it.

Signed-off-by: Yilin Chen <[email protected]>
2019-02-09 23:16:31 +01:00
Andreas Rottmann ce2147d2b6 Add a warning regarding the use of Stdin handles (#876)
Also see the discussion on issue #589.
2019-02-06 21:20:15 -08:00
Alan Somers fca41d4e73 Test FreeBSD on cirrus-ci.com (#873) 2019-02-06 21:19:54 -08:00
Carl Lerche a69aca850c Bump tokio-timer v0.2.10 (#886) 2019-02-04 16:09:43 -08:00
Zahari Dichev 13c96187f8 tokio-timer: Fix multi reset DelayQueue bug (#871)
Fixes #868
2019-02-04 14:37:58 -08:00
wangcong 61d4aa98e4 docs: replace Prepends with Appends (#882) 2019-02-04 09:46:02 -05:00
Carl Lerche 9d6d142bed Bump tokio-sync v0.1.1 (#881) 2019-02-01 14:19:34 -08:00
Stephen Carman 95b0eec8af sync: bounded channel can not have 0 size (#879) 2019-02-01 12:54:06 -08:00
Stjepan Glavina e1a07ce50c threadpool: update crossbeam dependencies (#874) 2019-01-30 14:08:43 -08:00
Carl Lerche 11e2af66a8 Bump Tokio to v0.1.15. (#869)
Also bumps:

- tokio-sync (0.1.0)
- tokio-threadpool (0.1.11)
- tokio-timer (0.2.9)
2019-01-25 10:20:09 -08:00
Carl Lerche a4aae1459c chore: move enumerate test to correct location (#867) 2019-01-24 20:47:45 -08:00
Zahari Dichev 12546d1d9c tokio-timer: fix DelayQueue bug when inserting shorter delay (#863)
Reset the delay of the queue in case an item that expires sooner than the last inserted is put
into the queue.
2019-01-24 14:36:41 -08:00
Zahari Dichev fbad6297c5 Add enumerate combinator to Stream (#832) 2019-01-24 11:50:34 -08:00
Jon Gjengset 0ec8986b0b Make reason for try_send errors clearer (#864) 2019-01-23 15:06:24 -08:00
Jon Gjengset c6f8bdb249 Remove T: Debug bound on mpsc Debug impls (#866)
Following from https://github.com/tokio-rs/tokio/pull/865, this PR
removes `#[derive(Debug)]` on `mpsc` sender and receiver types in favor
of explicit `impl fmt::Debug` blocks that don't have a `T: fmt::Debug`
bound.
2019-01-23 18:04:00 -05:00
Jon Gjengset c6f9a069a5 Explicit impl Clone for tx to avoid T: Clone (#865)
`#[derive(Clone)]` on a type `struct Foo<T>` adds an impl that requires that
`T: Clone`:

```rust
impl<T: Clone> Clone for Foo<T>
```

which is unfortunate in the case of senders, because we don't want to require
that the items being sent are `Clone` for the channel sender to be `Clone`.
This PR adds an explicit `impl Clone` for the bounded and unbounded sender
types which does not have the `T: Clone` bound.

Note that this is _also_ an issue with `#[derive(Debug)]`, but that one is
harder to work around as `chan::Tx` _also_ has `#[derive(Debug)]`, as does
`chan::Chan`, so we'd have to add explicit impls for all of them to make
progress.
2019-01-23 15:51:44 -05:00
Sean McArthur 9f356d6244 tokio-sync: add into_inner for TrySendErrors (#862) 2019-01-22 14:48:22 -08:00
Carl Lerche 13083153aa Introduce tokio-sync crate containing synchronization primitives. (#839)
Introduce a tokio-sync crate containing useful synchronization primitives for programs
written using Tokio.

The initial release contains:

* An mpsc channel
* A oneshot channel
* A semaphore implementation
* An `AtomicTask` primitive.

The `oneshot` and `mpsc` channels are new implementations providing improved
performance characteristics. In some benchmarks, the new mpsc channel shows
up to 7x improvement over the version provided by the `futures` crate. Unfortunately,
the `oneshot` implementation only provides a slight performance improvement as it
is mostly limited by the `futures` 0.1 task system. Once updated to the `std` version
of `Future` (currently nightly only), much greater performance improvements should
be achievable by `oneshot`.

Additionally, he implementations provided here are checked using
[Loom](http://github.com/carllerche/loom/), which provides greater confidence of
correctness.
2019-01-22 11:37:26 -08:00
rmcteggart-r7 91f20e33a4 docs: deal with Result instead of using unwrap (#860) 2019-01-20 14:21:17 -05:00
Eliza Weisman 983e9d1b67 timer: Fix DelayQueue delay reset logic (#851) 2019-01-20 08:38:39 -05:00
Stjepan Glavina 4c8f274db9 threadpool: drop incomplete tasks on shutdown (#722)
## Motivation

When the thread pool shuts down, futures that have been polled at least once but not completed yet are simply leaked. We should drop them instead.

## Solution

Multiple changes are introduced:

* Tasks are assigned a home worker the first time they are polled.

* Each worker contains a set of tasks (`Arc<Task>`) it is home to. When a task is assigned a home worker, it is registered in that worker's set of tasks. When the task is completed, it is unregistered from the set.

* When the thread pool shuts down and after all worker threads stop, the remaining tasks in workers' sets are aborted, i.e. they are switched to the `Aborted` state and their `Future`s are dropped.

* The thread pool shutdown process is refactored to make it more robust. We don't  track the number of active threads manually anymore. Instead, there's  `Arc<ShutdownTrigger>` that aborts remaining tasks and completes the `Shutdown` future once it gets destroyed (when all `Worker`s and `ThreadPool` get dropped because they're the only ones to contain strong references to the `ShutdownTrigger`).

Closes #424 
Closes #428
2019-01-17 22:12:25 +01:00
Marek Kotewicz c980837581 docs: missing links in tokio-timer::delay_queue (#845) 2019-01-13 21:20:08 +01:00
Marek Kotewicz eec370cae8 docs: fixed links in tokio-timer (#844)
* docs: fixed links in tokio-timer/src/timer/mod.rs

* docs: fixed links in tokio-timer::clock
2019-01-12 10:06:55 -08:00
Marek Kotewicz 733d432b80 docs: fixed links to tokio_timer::clock::Now (#842)
* docs: fixed links to tokio_timer::clock::Now in tokio-timer/src/timer/mod.rs

* docs: fixed links to std::time::Instant in tokio-timer/src/timer/mod.rs
2019-01-10 23:49:13 +01:00
Carl Lerche 74c473d68f travis: allow nightly Rust CI to fail (#843) 2019-01-10 11:27:58 -08:00
Sean McArthur d95c697781 tokio: update tokio-threadpool minimum version (#838) 2019-01-07 16:49:08 -08:00
Carl Lerche 25e835c5b7 tcp: specify version for tokio dev dependency
This is required for publishing to crates.io
2019-01-06 23:31:24 -08:00
Carl Lerche 961aae41c4 Bump version to 0.1.14. (#836)
Also bumps:

* tokio-async-await (0.1.5)
* tokio-executor (0.1.6)
* tokio-fs (0.1.5)
* tokio-io (0.1.11)
* tokio-reactor (0.1.8)
* tokio-tcp (0.1.3)
* tokio-threadpool (0.1.10)
* tokio-tls (0.2.1)
* tokio-uds (0.2.5)

...and updates LICENSE files to 2019.
2019-01-06 23:25:55 -08:00
Carl Lerche 74c73b218e Revert "util: implement stream debounce combinator (#747)" (#834)
This reverts commit 7a49ebb65e.

The commit conflicted with another change that was merged, causing CI to fail. The public API
also requires a bit more refinement (#833) and Tokio crates need to be released.
2019-01-06 16:56:49 -08:00
Moritz Gunz 7a49ebb65e util: implement stream debounce combinator (#747) 2019-01-05 11:08:12 -05:00
Stjepan Glavina a687922746 tcp: deprecate TcpStream::try_clone() (#824) 2019-01-05 10:55:58 -05:00
Stjepan Glavina df299ced45 threadpool: panic if a worker thread cannot be spawned (#826) 2019-01-05 10:53:38 -05:00
Carl Lerche 78d1fe0eb0 ci: limit min rust version to cargo check (#829) 2019-01-05 10:52:26 -05:00
Ryan Huang fc8cde383a docs: fix link to ThreadPool (#830) 2019-01-05 10:51:17 -05:00
Sean McArthur 76198f63d7 Provide optional features on tokio crate (#808)
Disabling all features means the only dependency is `futures`.

Relevant pieces of the API can then be enabled with the following features:

- `codec`
- `fs`
- `io`
- `reactor`
- `tcp`
- `timer`
- `udp`
- `uds`

This also introduces the beginnings of enabling only certain pieces of the `Runtime`. As a start, the entire default runtime API is enabled via the `rt-full` feature.
2019-01-04 11:42:33 -08:00
Carl Lerche 39dc5706b7 travis: remove commented out code. (#828)
The commented out lines are no longer relevant and will not be brought
back.
2019-01-03 22:04:09 -08:00
Carl Lerche cbecb87797 executor: fix build (#825)
Two unrelated PRs to the same file resulted in a broken build. This
patch fixes the build by including `Arc`.
2019-01-03 11:26:58 -08:00
Carl Lerche f0bdf1980c threadpool: remove unused fn (#822)
The unused lint on nightly has discovered a new unused fn.
2019-01-03 09:34:37 -08:00
Stjepan Glavina 5e2d93f060 Use Crossbeam's Parker/Unparker (#528) 2019-01-02 21:51:22 -08:00
Taiki Endo 9a8d087c69 Allow deprecated Error::cause (#818)
Error::cause is deprecated in Rust 1.33, but this allows Error::cause
until the minimum supported version of tokio is Rust 1.30.

When the minimum support version of tokio reaches Rust 1.30,
replace Error::cause with Error::source.

Fixes: #817
2019-01-02 14:12:11 -08:00
gralpli 30f59670c8 Clarify what NoopWaker does (#819) 2019-01-02 12:29:30 -08:00
jq-rs 9e4ddaeaf3 examples: single-threaded chat combinator example (#794) 2018-12-29 10:16:30 -05:00
Balthild Ires 03e2e864f3 Stablize pin feature (#814)
Box::pinned has been renamed to Box::pin. Meanwhile, the pin feature
no longer requires an attribute to enable.

Fixes: #813
2018-12-28 12:12:31 -08:00
Sean McArthur c8a990eda4 tokio-reactor: deprecates Handle::current() (#805)
The side effects of calling `Handle::current()` from outside of a
runtime could be very surprising, since it would start up a background
reactor.
2018-12-28 12:09:35 -08:00
Pavel Strakhov 1a5026324f executor: impl Unpark for Arc<Unpark> (#802) 2018-12-28 14:40:04 -05:00
Stjepan Glavina fdf4aba621 threadpool: introduce a global task queue (#798) 2018-12-28 14:34:54 -05:00
Roman 201b6ce53a ci: remove ALLOW_FAILURES=false in travis for nightly cargo doc (#816) 2018-12-28 10:06:00 -05:00
Roman db69275202 docs: fix warnings for nightly docs (#792) 2018-12-17 15:20:46 -05:00
Roman af85cb3430 ci: improve travis run times (#793) 2018-12-17 15:18:27 -05:00
Christian Bourjau 36f1a19ac8 Minor change in documentation of Decoder::decode (#797)
`None` -> `Ok(None)`
2018-12-13 11:14:38 -08:00
Stjepan Glavina 6aa990ea75 threadpool: fix semaphore deadlock (#795) 2018-12-12 16:42:18 -05:00
Simon Farnsworth 760a7667d6 threadpool: improve the documentation of blocking (#789) 2018-12-05 15:20:19 -05:00
Matt Gathu 2283b63e9e fs: added usage examples/doctests to File (#786) 2018-12-01 21:07:48 -05:00
Felix Obenhuber 8263e5f18d uds: fix WouldBlock case in UnixDatagram send methods (#782) 2018-11-30 19:40:03 -05:00
Carl Lerche b3e57b60d0 examples: remove reference to tokio-core (#780) 2018-11-28 14:55:31 -05:00
Matt Gathu 1cd0ebfc5e tcp: add usage examples to TcpListener and TcpStream (#775)
Refs: https://github.com/rust-lang-nursery/wg-net/issues/54
2018-11-28 13:05:35 -05:00
David Kellum 4797d79950 reactor: update to parking_lot 0.7 (#778) 2018-11-28 09:29:31 -08:00
Steven Fackler e7d9ba7e51 tls: make TlsConnector and TlsAcceptor derive Clone (#777) 2018-11-27 07:52:17 -05:00
luben karavelov 527dc0a66f net: export UnixDatagram and UnixDatagramFramed (#772) 2018-11-23 08:41:32 -05:00
Carl Lerche b117fc1d65 Bump version to v0.1.13 (#771)
This also bumps the following sub crate versions:

* tokio-current-thread (0.1.4)
* tokio-reactor (0.1.7)
* tokio-signal (0.2.7)
* tokio-threadpool (0.1.9)
* tokio-timer (0.2.8)
* tokio-udp (0.1.3)
* tokio-uds (0.2.4)
2018-11-21 17:11:31 -08:00
Felix Obenhuber 272e09d349 threadpool: remove smoke example (#764) (#770) 2018-11-21 14:23:36 -08:00
Stjepan Glavina 3235749006 threadpool: refactor pool shutdown (#769) 2018-11-20 21:43:23 +01:00
Stjepan Glavina 9c037044c4 threadpool: rename inner to something more descriptive (#768)
`inner` is a fitting name for variables of type named `Inner`, but in other cases I find them confusing - sometimes `inner` refers to a `Pool`, sometimes to a `Sender`. I renamed a bunch of variables named `inner` to be more descriptive.

This PR is the first step in an effort of splitting https://github.com/tokio-rs/tokio/pull/722#issuecomment-439552671 into multiple PRs.
2018-11-20 20:05:14 +01:00
Patrick Barrett 3658e10045 uds: implement UnixDatagramFramed (#453)
Implement `Stream + Sink` layer on top of unix domain sockets
using codecs.
2018-11-20 09:19:34 -08:00
Carl Lerche ed3ece266b current-thread: fix shutdown on idle (#763)
When spawning using `Handle` while on the executor, tasks were being
double counted. This prevented the number of active tasks to reach zero,
thus preventing the executor from shutting down.

This changes `spawn` to check if being called from the executor
**before** incrementing the number of active tasks.

Fixes #760
2018-11-20 09:17:07 -08:00
Liran Ringel 9b1a45cc6a tests: handle errors properly in examples (#748) 2018-11-20 11:10:36 -05:00
Carl Lerche 477fa5580a ci: Don't deploy docs if $TARGET is set (#762) 2018-11-19 21:22:28 -08:00
Toby Lawrence bb6cca8ff0 tests: switch to Windows Server 2016 for AppVeyor builds. (#761)
Should hopefully fix the underlying bug that was causing tokio-tls tests to occasionally fail on Windows.

Signed-off-by: Toby Lawrence <[email protected]>
2018-11-19 20:18:37 -05:00
Moritz Gunz e166c4d912 Implement throttle combinator (#736)
Throttle down a stream by enforcing a fixed delay between items.
2018-11-19 15:04:55 -08:00
Toby Lawrence b7506cf663 Allow nightly builds to fail. (#743)
* tests: allow nightly builds to fail

Signed-off-by: Toby Lawrence <[email protected]>
2018-11-19 17:13:56 -05:00
Carl Lerche dc4a29359f io: allow deprecated code in length_delimited test (#759)
This file is testing deprecated code, so it should be permitted to
access deprecated code.
2018-11-19 14:11:46 -08:00
Bastian Köcher d3dca4552b Expose after_start and before_stop in runtime::Builder (#756)
Closes #705
2018-11-19 09:04:58 -08:00
andoks 42a0df1ea4 Fix async await README example (#758)
* async-await: fix README example dependencies

As per commit "async-await: track nightly changes (#661)" ( commit
2f690d30bc)

> The `tokio-async-await` crate is no longer a facade. Instead, the
> `tokio` crate provides a feature flag to enable async/await support.

Ensure the example in the async-await README file also works by
correctly declaring this updated dependency

* async-await: remove unnecessary 'edition' declaration from README

As the "edition" feature was stabilized in rust v1.30 and async-await
specifies that the nightly toolchain must be used, remove the use of the
"edition" feature gate since it is enabled by default.
2018-11-17 20:58:19 -08:00
Brian Myers a98eab6eff rt: fix Builder docs to no longer use deprecated methods (#749) 2018-11-16 14:58:08 -08:00
Ivan Petkov 5a5dde70b3 signal: miscellaneous tweaks and improvements (#751)
* Minimize allocation needed for channels

* Use a newtype for signal ids

* We can just cast the raw pointer to a `usize` and still perform a
simple identity check, without incurring any implications of storing a
raw pointer (e.g. previously Signal was !Sync and had an unsafe impl of
Send, and now it is naturally Sync+Send)

* Broadcast with `try_send` instead of `start_send`

The `Stream::start_send` method uses backpressure and schedules the
current task to be notified whenever the channel has additional room,
which means we'll generate a lot of unnecessary wakeups whenever a
channel gets full

By changing to `try_send` and handling any errors, we ensure the
Driver's task won't get woken up when a Signal finally consumes its
notification, since we're coalescing things anyway
2018-11-16 14:56:43 -08:00
Alex Gaynor d0963774a3 chore: bump rand dependency to 0.6 (#753) 2018-11-16 14:54:14 -08:00
Felix Obenhuber c83355235c uds: minor doc fix in UnixStream and UnixDatagram (#754) 2018-11-16 14:53:19 -08:00
Kazuyoshi Kato 33a216e4c1 fs: add more tests (#755)
Fixes #704.
2018-11-16 14:50:06 -08:00
Toralf Wittner 09f2ac85bf udp: add into_parts to RecvDgram (#710)
* udp: add `into_parts` to `RecvDgram`

If `RecvDgram` can not be driven to completion it may become necessary to get back the `UdpSocket` it contains which is currently not possible.

This adds`into_parts` to get the socket as well as the buffer back. Both methods consume `RecvDgram`.

Note that after the future has completed, `into_parts` must not be used, or else a panic will happen.
2018-11-15 10:55:34 -05:00
Ohad Ravid 32a152630f uds: added solaris support in the ucred module (#733) 2018-11-15 10:30:37 -05:00
Kazuyoshi Kato 9153067d66 fs: add tests for directory-related functions (#704) (#724)
This change adds a few tests around directory-related functions.
2018-11-13 18:28:52 -05:00
Kazuyoshi Kato d246964bdf fs: gen_ascii_chars has been deprecated (#735)
Use sample_iter() instead.
2018-11-10 21:35:38 -05:00
Alex Gaynor e700607554 Bumped crossbeam-utils version (#746)
## Motivation

tokio depends on an out of date version of crossbeam-utils, which results in multiple versions of that package being linked in binaries which use other popular libraries.

## Solution

Bump the version; there's no API changes and tests still pass.
2018-11-10 10:39:09 +01:00
Benjamin Saunders 5321550534 Derive Clone for delay_queue::Key (#730)
Improves API ergonomics with minimal forwards-compatibility hazard.
2018-11-09 15:11:17 -08:00
Stjepan Glavina 32e1cafb57 fix tsan errors (#745) 2018-11-09 15:06:46 -08:00
Josh Leverette 49bc4025dd reactor: reduce log level of loop process (#734) 2018-11-07 16:53:53 -05:00
Carl Lerche 51e36e41bc Add tokio-buf and a BufStream trait (#611)
The `BufStream` trait provides an improved API for working with
asynchronous streams of bytes compared to `Stream<Item = [u8]>`
2018-10-29 13:43:48 -07:00
Carl Lerche d011b92b9a rt: fix Runtime::reactor() as used by tokio-core (#721)
* rt: fix `Runtime::reactor()` as used by tokio-core

Up until Tokio v0.1.11, the handle returned by `Runtime::reactor()`
pointed to a reactor instance running in a background thread. The thread
was eagerly spawned.

As of v0.1.12, a reactor instance is created per runtime worker thread.
`Runtime::reactor()` was deprecated and updated to point to the reactor
for one of the worker threads.

A problem occurs when attempting to use the reactor before spawning a
task. Worker threads are spawned lazily, which means that the reactor
referenced by `Runtime::reactor()` is not yet running.

This patch changes `Runtime::reactor` back to a dedicated reactor
running on a background thread. However, the background thread is now
spawned lazily when the deprecated function is first called.

Fixes #720

* Fix comment

Co-Authored-By: carllerche <[email protected]>
2018-10-25 11:23:54 +02:00
Carl Lerche f929576f0e Bump version to 0.1.12 (#718)
Also bumps the following sub-crates:

* tokio-fs (0.1.4)
* tokio-io (0.1.10)
* tokio-signal (0.2.6)
* tokio-threadpool (0.1.8)
* tokio-uds (0.2.3)
2018-10-23 22:00:49 -07:00
Ivan Petkov b0f001a05a signal: Bump version to 0.2.6 (#714)
* Also Update the CHANGELOG to match the rest of the project
2018-10-23 20:39:19 -07:00
Iku Iwasa 2291ba9d0d uds: add NetBSD support (#715) 2018-10-23 20:15:42 -04:00
Name 7f84f6b4ca contributing: fix an invalid link (#716)
Just move a dot to the right place.
2018-10-21 16:56:01 +00:00
Andrew Audibert 5f61bd5252 fix a typo in the contributing guide (#711) 2018-10-19 09:25:11 -07:00
Ryan Dahl bffa3ed558 fs: expose fs::File::from_std() (#696) 2018-10-17 19:51:46 -04:00
Sean McArthur 7b5ef61aeb runtime: check Enter in more places when blocking (#708)
- `tokio::run` checks Enter before creating a new threadpool and
  spawning the main future.
- `Runtime::block_on` now checks Enter
- `Runtime::block_on_all` now checks Enter
2018-10-17 15:25:40 -07:00
Stjepan Glavina 753336de8e threadpool: Arc instead of Inner in Notifier (#702) 2018-10-15 13:24:00 -07:00
Ryan Levick 65aea16ad1 tokio: change hello world to new, simpler example (#690) 2018-10-12 12:42:19 -04:00
nickelc 796fee6364 fs: fix minor documentation error for MetadataFuture (#698) 2018-10-12 12:41:19 -04:00
Stjepan Glavina adb0ba71d4 threadpool: worker threads shouldn't respect keep_alive (#692)
<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.

Bug fixes and new features should include tests.

Contributors guide: https://github.com/tokio-rs/tokio/blob/master/CONTRIBUTING.md
-->

## Motivation

Now that each worker thread drives its own reactor, reactors have to be driven until the threadpool shuts down. We mustn't use the `keep_alive` setting to shut down a worker thread if it doesn't receive an event from the reactor for a certain duration of time.

<!--
Explain the context and why you're making that change. What is the problem
you're trying to solve? In some cases there is not a problem and this can be
thought of as being the motivation for your change.
-->

## Solution

Just ignore the `keep_alive` setting when parking in `Worker::sleep`.

<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->
2018-10-10 09:05:36 +02:00
David Ross bfa6766f3c re-export tokio_io::read in tokio::io (#689)
Fixes: #688
2018-10-09 19:50:03 -07:00
Nikolay Kim a2f457fa48 io: expose underlying codec (#686) 2018-10-06 19:23:05 -04:00
Eliza Weisman 1879bc49ce codec: Fix panic in LengthDelimitedCodec::encode (#682)
Fixes: #681 

## Motivation

Currently, a potential panic exists in `LengthDelimitedCodec::encode`.
Writing the length field to the `dst` buffer can exceed the buffer
capacity, as `BufMut::put_uint_{le,be}` doesn't reserve more capacity. 

## Solution

This branch adds a call to `dst.reserve` to ensure that there's 
sufficient remaining buffer capacity to hold the length field and
the frame, prior to writing the length field. Previously, capacity
was only reserved later in the function, when writing the frame
to the buffer, and we never reserved capacity for the length field.

I've also added a test that reproduces the issue. The test panics on
master, but passes after making this change.

Signed-off-by: Eliza Weisman <[email protected]>
2018-10-04 12:46:57 -07:00
Sven Marnach 678f6382b8 io: implement prepare_uninitialized_buffer for Take and Chain (#678) 2018-10-04 11:03:43 -07:00
Stjepan Glavina e27b0a46ba threadpool: spawn new tasks onto a random worker (#683)
* threadpool: submit new tasks to a random worker

* Revert unnecessary version bumps
2018-10-03 23:09:20 +02:00
Stjepan Glavina d35d0518f5 runtime: create reactor per worker (#660) 2018-10-02 18:19:27 -07:00
Sven Marnach 886511c0a6 io: fix minor documentation errors for Async{Read,Write} (#677) 2018-10-01 19:34:24 -04:00
Steven Fackler d06bd6b216 Expose keep_alive on the Runtime builder (#676)
This was overlooked when delegating the rest of the threadpool builder
methods from Runtime's builder.
2018-09-28 21:00:50 -07:00
Carl Lerche 2c85cd0991 Bump version to v0.1.11 (#675)
This fixes the dependency on `tokio-async-await` to not be scoped to
unix platforms.

Fixes #673
2018-09-28 11:32:52 -07:00
Carl Lerche 1e45237a28 Bump tokio-uds to v0.2.2 2018-09-27 20:05:23 -07:00
Sean McArthur 3a88d85538 ads: fix UdsStream::read_buf to clear read (not write) readiness (#672) 2018-09-27 20:02:29 -07:00
Carl Lerche b47ad24268 Bump version to v0.1.10, fixing minimal versions (#671)
Some minimal versions were not correctly updated.

Also updates:

* tokio-current-thread (v0.1.3).
2018-09-27 13:00:53 -07:00
Carl Lerche cab9a44e01 Bump version to v0.1.9 (#666)
This also includes bumps to subcrates.

* tokio-async-await (0.1.4)
* tokio-codec (0.1.1)
* tokio-current-thread (0.1.2)
* tokio-executor (0.1.5)
* tokio-io (0.1.9)
* tokio-reactor (0.1.6)
* tokio-tcp (0.1.2)
* tokio-threadpool (0.1.7)
* tokio-timer (0.2.7)
2018-09-26 22:32:51 -07:00
Carl Lerche 964afb2ce3 split facade modules into separate files (#665) 2018-09-26 15:28:57 -07:00
Carl Lerche 2f690d30bc async-await: track nightly changes (#661)
The `tokio-async-await` crate is no longer a facade. Instead, the `tokio` crate
provides a feature flag to enable async/await support.
2018-09-26 10:10:47 -07:00
Stjepan Glavina 331a88cee6 reactor: turn bench-poll into a proper benchmark (#662) 2018-09-26 08:52:35 -07:00
Andrew Tunnell-Jones 46353737e7 tinydb: Update doc to reflect change from RefCell to Mutex (#663)
Fixes: #658
2018-09-26 11:47:31 +02:00
Carl Lerche ffd73a64e7 async-await: streaming hyper body example (#656)
Add reading the hyper body in the async/await example.
2018-09-21 19:58:46 -07:00
Toby Lawrence 1119d572ee io: ensure ReadHalf/WriteHalf do not return WouldBlock directly (#655)
* io: ensure ReadHalf/WriteHalf do not return WouldBlock directly

These facades were passing back WouldBlock when the internal BiLock
couldn't be acquired, which does not fit the intended behavior.

Signed-off-by: Toby Lawrence <[email protected]>

* io: pull from the local crate, not crates.io
2018-09-21 14:59:07 -04:00
Stjepan Glavina 20ca59114a threadpool: impl Drop for Queue (#649)
We need to drain the queue when dropping, or else those `Arc<Task>`s
will be leaked.

Fixes #542
2018-09-21 10:20:41 -07:00
Eliza Weisman 3dd95a9ff1 Add max line length to LinesCodec (#632)
## Motivation

Currently, there is a potential denial of service vulnerability in the
`lines` codec. Since there is no bound on the buffer that holds data
before it is split into a new line, an attacker could send an unbounded
amount of data without sending a `\n` character. 

## Solution

This branch adds a `new_with_max_length` constructor for `LinesCodec`
that configures a limit on the maximum number of bytes per line. When
the limit is reached, the the overly long line will be discarded (in 
`max_length`-sized increments until a newline character or the end of the
buffer is reached. It was also necessary to add some special-case logic
to avoid creating an empty line when the length limit is reached at the 
character immediately _before_ a `\n` character.

Additionally, this branch adds new tests for this function, including a
test for changing the line limit in-flight.

## Notes

This branch makes the following changes from my original PR with
this change (#590):

- The whole too-long line is discarded at once in the first call to `decode`
  that encounters it.
- Only one error is emitted per too-long line.
- Made all the changes requested by @carllerche in
  https://github.com/tokio-rs/tokio/pull/590#issuecomment-420735023

Fixes: #186 

Signed-off-by: Eliza Weisman <[email protected]>
2018-09-20 17:08:00 -07:00
Sven Marnach be67eda117 fix deprecation warning in test for FutureExt::deadline() (#651)
* silence deprecation warnings for deadline in tests
* add new integration test for timeout
2018-09-20 15:26:56 -07:00
Alexander Polakov e267a1922d Reexport TaskExecutor from tokio_current_thread (#652) 2018-09-19 14:46:13 -07:00
Eliza Weisman 9b456f48d9 Set RUST_BACKTRACE=1 on AppVeyor (#650)
## Motivation

Currently, the `RUST_BACKTRACE` environment variable is set to `1` on
Travis CI builds:
https://github.com/tokio-rs/tokio/blob/0ca973a7ebc5b8a29beac1ccb6c73ef26ddcbf22/.travis.yml#L49
However, it's not set on AppVeyor. This can make debugging
Windows-specific CI failures challenging for developers on other
operating systems.

## Solution

This branch sets `RUST_BACKTRACE=1` on AppVeyor.

Signed-off-by: Eliza Weisman <[email protected]>
2018-09-19 11:53:11 -07:00
Eliza Weisman 0ca973a7eb tokio: deprecate and replace runtime::threadpool_builder (#645)
* Deprecate and hide runtime::Builder::threadpool_builder

* Add functions to runtime::Builder wrapping threadpool builder functions

Signed-off-by: Eliza Weisman <[email protected]>
2018-09-19 10:37:45 -04:00
RT df6acf0c2a tokio-timer: reset timeout after elapsed in stream (#648) 2018-09-19 09:47:39 -04:00
Eliza Weisman 98d23b8b29 Make tokio::run panic if called from inside tokio::run (#646)
This is implemented by creating an `Enter` instance from within `run`.

This patch also introduces `Enter::block_on`.

Fixes #504
2018-09-18 21:57:21 -07:00
Eliza Weisman 85f8522536 tokio-executor: hide deprecated tokio-threadpool reexports (#644)
Fixes: #643
Signed-off-by: Eliza Weisman <[email protected]>
2018-09-18 23:57:17 -04:00
Liran Ringel d275341fb2 Fix tokio-async-await tests compile errors (#630) 2018-09-18 13:49:08 -07:00
Nick Cameron d735e5d527 async-await: update deps in tokio-async-await (#639) 2018-09-18 10:08:35 -07:00
Carl Lerche 4019198706 Add some missing future::Executor implementations (#563)
This adds an implementation of future::Executor for
`executor::DefaultExecutor` and `runtime::current_thread::Handle`.
2018-09-17 22:23:48 -07:00
Ivan Petkov 24dc85dc5e ci: Run cargo test with the --no-fail-fast flag (#635)
Since the CI runs all tests for all tokio crates, it is possible that a
sporadic failure in one crate can mask failures/successes of other
crates' tests.

Using the `--no-fail-fast` flag instructs cargo to run *all* tests
before failing the build. This will allow checking to see if any
relevant test cases still pass even if an unrelated test has failed.
2018-09-15 00:41:41 +00:00
Ivan Petkov aaa5adb7fd Merge pull request #634 from vorner/import-signal-2
Import the `tokio-signal` source from its original repo

Original repository can be found at https://github.com/alexcrichton/tokio-signal
2018-09-14 22:58:19 +00:00
Michal 'vorner' Vaner 5f68b3aaa1 signal: Remove Apache license
Whole tokio is MIT only, unifying.
2018-09-14 23:28:56 +02:00
Michal 'vorner' Vaner 2f69acbe9f signal: Fix tests after importing & linking
* Don't use tokio-core any more for tests. That one brings tokio from
  crates.io instead of the current workspace and two versions of that
  don't want to cooperate.
* Guard unix-specific examples on windows.
* Leave CI setup to top-level directory.
2018-09-14 23:28:47 +02:00
Michal 'vorner' Vaner 7e12f5c39e signal: Link tokio-signal and tokio crates
References in the Cargo.toml, various links.
2018-09-14 23:28:33 +02:00
Michal 'vorner' Vaner 462882b356 Merge tokio with tokio-signal 2018-09-14 23:27:22 +02:00
Michal 'vorner' Vaner 35687f1d18 signal: Move to tokio-signal subdirectory
As a preparation to merge with tokio.
2018-09-14 23:25:57 +02:00
Michal 'vorner' Vaner e7dc3a1091 signal: Use signal-hook for registration of signals
This saves some code and gets rid of quite some amount of unsafe code.
2018-09-14 23:25:21 +02:00
Ivan Petkov b594e240f9 signal: Bump version to 0.2.5 2018-09-14 23:25:21 +02:00
Ivan Petkov 605708dca6 signal: Fix a possible starvation with concurrent Signal polls
* Originally reported in alexcrichton/tokio-process#42
* The root cause appears to be due to two different PollEvented
instances trying to consume readiness events from the same file
descriptor.
* Previously we would simply swallow any `AlreadyExists` errors when
attempting to register the pipe receiver with the event loop. I'm not
sure if this means the PollEvented wrapper wasn't fully registered to
receive events, or maybe there is a potential race condition with how
PollEvented consumes mio readiness events. Using a fresh/duplicate file
descriptor appears to mitigate the issue, however.
* I was also not able to reproduce the issue as an isolated test case so
there is no regression test available within this crate (but we can add
one in tokio-process)
2018-09-14 23:25:08 +02:00
Carl Lerche cc40a4e7f0 Revert "Add max line length to LinesCodec (#590)"
This reverts commit 4ae6c997ee.
2018-09-12 10:34:37 -07:00
Eliza Weisman 4ae6c997ee Add max line length to LinesCodec (#590)
* codec: add new constructor `with_max_length ` to `LinesCodec`
* codec: add security note to docs

Signed-off-by: Eliza Weisman <[email protected]>

* Fix Rust 1.25 compatibility

* codec: Fix incorrect line lengths in tests (and add assertions)

Signed-off-by: Eliza Weisman <[email protected]>

* codec: Fix off-by-one error in lines codec

Signed-off-by: Eliza Weisman <[email protected]>

* codec: Fix call to decode rather than decode_eof in test

Signed-off-by: Eliza Weisman <[email protected]>

* codec: Fix incorrect LinesCodec::decode_max_line_length

This bug was introduced after the fix for the off-by-one error.
Fortunately, the doctests caught it.

Signed-off-by: Eliza Weisman <[email protected]>

* codec: Minor style improvements

Signed-off-by: Eliza Weisman <[email protected]>

* codec: Don't allow LinesCodec length limit to be set after construction

Signed-off-by: Eliza Weisman <[email protected]>

* codec: change LinesCodec to error and discard line when at max length

* codec: Fix build on Rust 1.25

The slice patterns syntax wasn't supported yet in that release.

Signed-off-by: Eliza Weisman <[email protected]>

* codec: Add test for out-of-bounds index when peeking

Signed-off-by: Eliza Weisman <[email protected]>

* codec: Fix out of bounds index

* codec: Fix incomplete comment

Signed-off-by: Eliza Weisman <[email protected]>

* codec: Add test for line decoder buffer underrun
2018-09-12 13:02:57 -04:00
Stjepan Glavina 0f44adf5f6 reactor: use LocalKey::try_with in sharded RW lock (#628)
@jonhoo reported a panic in the call to `LocalKey::with`, which occurs
when the reactor is dropped in the middle of TLS teardown. This PR
changes the call to `LocalKey::try_with` and handles the case when the
thread-local value has already been destroyed.
2018-09-11 16:48:06 -04:00
Flux Xu 19d5565442 Expose thread_pool::SpawnHandle (#604) 2018-09-10 15:51:15 -07:00
Ivan Petkov 98e76d9bc6 signal: Bump version to to 0.2.4 2018-09-10 11:30:08 -07:00
Alan Somers b7f5bc95fe signal: Actually make unix::bsd public 2018-09-10 11:30:07 -07:00
Ivan Petkov 90ea2f6c5b signal: Bump version to 0.2.3 2018-09-10 11:30:07 -07:00
Ivan Petkov 837c3934d5 signal: Also cfg gate the entire unix::bsd module 2018-09-10 11:30:07 -07:00
Alan Somers bcd42d11d9 signal: Move SIGINFO to a BSD-specific submodule 2018-09-10 11:30:07 -07:00
Alan Somers 8ad66d296f signal: Add CHANGELOG entry for SIGINFO. 2018-09-10 11:30:07 -07:00
Alan Somers d9edc26e97 signal: export SIGINFO on supported platforms. 2018-09-10 11:30:07 -07:00
Alan Somers f0ac62151b signal: Update tokio dependency
tokio::runtime::current_thread was added in 0.1.6
2018-09-10 11:30:06 -07:00
Ivan Petkov 214722a296 signal: Update CHANGELOG 2018-09-10 11:30:06 -07:00
Niv Kaminer b8f8145b62 signal: cast SIGINFO to be the same type as sa_flags regardless of platform 2018-09-10 11:30:06 -07:00
Ivan Petkov 32d3e0e1f9 signal: Bump version to 0.2.2 2018-09-10 11:30:06 -07:00
Ivan Petkov 266919add6 signal: Refactor Signal tests
* Added timeouts to all tests that were missing them
 - any issue we have will likely result in deadlocks/starvation so its
   best if all tests quickly timeout rather than require getting killed
   or have the CI timeout itself
* Added a `support` module and put a bunch of helpers there to DRY the
tests
2018-09-10 11:30:06 -07:00
Ivan Petkov c9ffd98b1e signal: Fix a potential Signal starvation based on creation order
* As observed in alexcrichton/tokio-signal#38, Signal instances can starve based on the order
they are created in, and this ordering appears to be platform/OS
specific
* The crux of the issue is that we woud only *attempt* to broadcast any
pending signals if we successfully read out at least one byte from the
global pipe.
* For reasons unclear to me, the affected Signal instance would get
woken up after the signal handler writes to the global pipe, but it
would immediately hit a WouldBlock error and give up, bypassing the
broadcast attempt (even though the pending flag was correctly set).
 - Maybe this has to do with OS specifics with how the bytes are
   delivered (or not), or with some complex interaction with tokio and
   the pipe registration. It seems fishy since strace logs didn't show
   the signal handler pipe write fail either, but I'm all out of ideas
* The fix appears simple: unconditionally attempt to broadcast any
pending signals *any* time a Driver instance is woken up.
* Since we perform an atomic check for each pending signal, we know that
each (coalesced) signal broadcast will happen at most once. If we were
supuriously woken up and no signals were pending, then nothing will be
yielded to any pollers of Signal
* The down side is that since each Signal instance polls a Driver
instance, each poll to Signal will essentially perform N atomic
operations (N = number of signals we support) in an attempt to broadcast
any pending signals.
 - However, we can revisit optimizing this better in the future

Fixes alexcrichton/tokio-signal#38
2018-09-10 11:30:06 -07:00
Ivan Petkov 2d4bfa1485 signal: Fix starvation of signal streams on drop of another instance
* We introduce a new global structure which keeps track of how many
signal streams have been registered with a given event loop (the event
loop is identified by its OS file descriptor)
* We only attempt to deregister our global evented pipe from any event
loop if and only if we are the last signal that was registered with it
2018-09-10 11:30:05 -07:00
Ivan Petkov b6ecfa251c signal: Add (failing) test case which exibits starvation on drop
* Currently, whenever a new signal stream is created we attempt to
register a global pipe with the event loop to drive events.
* We also (correctly) swallow any descriptor-already-registered errors
since the same pipe is always used
* However, we currently *deregister* the same global pipe *any time* a
Signal stream is dropped.
* This means that if 2 or more of Signal instances exist simultaneously
(even if listening for different signals) and one of them is dropped,
the remainder will starve (until any new signal is created again).
2018-09-10 11:30:05 -07:00
Ivan Petkov 3a81d7746a signal: Split up all integration tests to run in their own process
* Cargo runs each integration-style-test in its own process. Since the
tests use global data structures specific to the process, we should run
them in an isolated manner to avoid having cross-test interactions
* Fixes alexcrichton/tokio-signal#39
2018-09-10 11:30:05 -07:00
Daniel Wagner-Hall 6e1a833825 signal: Update mio dependency to 0.6.14
This allows tokio-signal to build with `-Z minimal-versions` - see
https://github.com/rust-lang/cargo/issues/5657#issuecomment-401110172
for more details.

Earlier versions depend on log 0.3.1, which itself depends on libc
0.1, which doesn't build on any post-1.0 version of rust.
2018-09-10 11:30:05 -07:00
Niv Kaminer 3f80953dee signal: account for definition mismatch on aarch64 android 2018-09-10 11:30:05 -07:00
Michael Hadley 4374f5be70 signal: Fix typo in README.md 2018-09-10 11:30:05 -07:00
jjl b23ab94cd5 signal: Change reference from 'tokio-core' to 'tokio' in README 2018-09-10 11:30:04 -07:00
Markus Westerlind 40c77bd17e signal: Version 0.2 2018-09-10 11:30:04 -07:00
Markus Westerlind 31b51004f2 signal: Increase number of signals to 33 for the sake of FreeBSD
Fixes alexcrichton/tokio-signal#21
2018-09-10 11:30:04 -07:00
Markus Westerlind 9a4e4f2308 signal: Don't use the depreceated new method of Registration 2018-09-10 11:30:04 -07:00
Markus Westerlind 484fda7a23 signal: Add an appveyor build file
It is not possible to test much on windows but this will at least verify
that it can be built
2018-09-10 11:30:04 -07:00
Markus Westerlind 45ba6e2652 signal: Remove test that were accidentally included in the ctrl-c example 2018-09-10 11:30:04 -07:00
Markus Westerlind e73b8a0cc9 signal: refactor: Prefer the implicit handle passing used by tokio 2018-09-10 11:30:03 -07:00
Markus Westerlind 209232befd signal: Ensure that the driver dies once the signal does
`tokio::run` expects that all futures finish processing so we can't
leave `Driver` around forever or `tokio::run` would never return.
2018-09-10 11:30:03 -07:00
Markus Westerlind f759e4d70f signal: panic 2018-09-10 11:30:03 -07:00
Markus Westerlind 1fdff707b8 signal: test: Add a test for ctrl_c on unix 2018-09-10 11:30:03 -07:00
Markus Westerlind e97e8cb7fe signal: Update the windows implementation to work with tokio
BREAKING CHANGE

`ctrl_c` now takes a `tokio_reactor::Handle`
2018-09-10 11:30:03 -07:00
Markus Westerlind 2848df9b6c signal: Run rustfmt 0.4.2 2018-09-10 11:30:03 -07:00
Alex Crichton 7a24ed7509 signal: Bump to 0.1.5 2018-09-10 11:30:02 -07:00
Alex Crichton 9c9760cfbb signal: Fix a bug with most recent tokio-core release 2018-09-10 11:30:02 -07:00
Alex Crichton 5ecd929b1a signal: Bump to 0.1.4 2018-09-10 11:30:02 -07:00
Alex Crichton 8ddebf4309 signal: Fix compile on Android
Closes alexcrichton/tokio-signal#19
2018-09-10 11:30:02 -07:00
Alex Crichton 0df1882f21 signal: Bump to 0.1.3 2018-09-10 11:30:02 -07:00
Alex Crichton 4fa1b2b58c signal: Update to winapi 0.3 2018-09-10 11:30:02 -07:00
Alex Crichton a4895fe364 signal: Tweak travis config 2018-09-10 11:30:02 -07:00
Alex Crichton 7ab97f99c8 signal: Clarify wording of license information in README.
This text historically was copied verbatim from rust-lang/rust's own README [1]
with the intention of licensing projects the same as rustc's own license, namely
a dual MIT/Apache-2.0 license. The clause about "various BSD-like licenses"
isn't actually correct for almost all projects other than rust-lang/rust and
the wording around "both" was slightly ambiguous.

This commit updates the wording to match more precisely what's in the
standard library [2], namely clarifying that there aren't any BSD-like licenses
in this repository and that the source is licensable under either license, at
your own discretion.

[1]: https://github.com/rust-lang/rust/tree/f0fe716dbcbf2363ab8f929325d32a17e51039d0#license
[2]: https://github.com/rust-lang/rust/blob/f0fe716dbcbf2363ab8f929325d32a17e51039d0/src/libstd/lib.rs#L5-L9
2018-09-10 11:30:01 -07:00
Alex Crichton 9bf3228f73 signal: Add an example for waiting on two signals
Relies on `Stream::select` to merge streams.

Closes alexcrichton/tokio-signal#16
2018-09-10 11:30:01 -07:00
Raphael Nestler d41c60e21d signal: Fix typo in README 2018-09-10 11:30:01 -07:00
Jules Kerssemakers 934c596133 signal: Ctrl+C example: quit after 10 signals. 2018-09-10 11:30:01 -07:00
Jules Kerssemakers 72e2209bd8 signal: Ctrl+C example: more explanations 2018-09-10 11:30:01 -07:00
Jules Kerssemakers 6a7092b9f7 signal: Ctrl+C example: Defer stream initialisation (and explain how/why) 2018-09-10 11:30:01 -07:00
Jules Kerssemakers 1c893ef6d3 signal: undo nested example cargo project
.. after learning about `cargo run --example`
2018-09-10 11:30:00 -07:00
Jules Kerssemakers 20e7598e8d signal: Ctrl+C example: Don't forget proper attribution for original example 2018-09-10 11:30:00 -07:00
Jules Kerssemakers 3db92496f6 signal: Ctrl+C example: highlight power of Stream::for_each() 2018-09-10 11:30:00 -07:00
Jules Kerssemakers da47cfbd58 signal: Ctrl+C example: clarify control flow after receiving Ctrl+C: unreachable!() 2018-09-10 11:30:00 -07:00
Jules Kerssemakers f5eadc74f1 signal: Ctrl+C example: add explanatory comments 2018-09-10 11:30:00 -07:00
Jules Kerssemakers 175f9afea9 signal: ctrl+C example: Prompt user to do something.
So we don't stay at a blank terminal without any feedback after `cargo run`
2018-09-10 11:30:00 -07:00
Jules Kerssemakers 48eda3fe2f signal: Upgrade ctrl+c example into cargo run-able version with proper Cargo.toml 2018-09-10 11:29:59 -07:00
Alex Crichton 010c2223ca signal: Touch up the sighup-example slightly 2018-09-10 11:29:59 -07:00
Jules Kerssemakers 36b58d8fa8 signal: new example: SIGHUP, shows how to receive other signals than ctrl+C 2018-09-10 11:29:59 -07:00
Alex Crichton c601f68c9f signal: Add some examples to crate docs
Closes alexcrichton/tokio-signal#11
2018-09-10 11:29:59 -07:00
Alex Crichton 78ca103f3a signal: Update to tokio-io 2018-09-10 11:29:59 -07:00
Michal 'vorner' Vaner 7da00f3832 signal: Use IDs that don't run out
Replace the sequential counting (which might be exhausted) by an address
of an object (in a box, so it doesn't change). This is also a unique, so
it is acceptable ID.
2018-09-10 11:29:59 -07:00
Michal 'vorner' Vaner edba77e8df signal: A test running multiple event loops
Run multiple loops (both in parallel and sequentially) to make sure
broadcasting to multiple of them works and we work even after the
initial loop has gone away.
2018-09-10 11:29:58 -07:00
Michal 'vorner' Vaner cf1afd2d90 signal: Style: Replace tabs with spaces
Mixing tabs and spaces breaks indentation for people (and github) if
they use different tab width.
2018-09-10 11:29:58 -07:00
Alex Crichton 8e58a9d8d4 signal: Add badges/categories 2018-09-10 11:29:58 -07:00
Alex Crichton 4afef9391a signal: Bump to 0.1.2 2018-09-10 11:29:58 -07:00
Alex Crichton b6bacc1ca3 signal: Clarify a comment 2018-09-10 11:29:58 -07:00
Alex Crichton 955cd2836d signal: Clear out old Signal on drop 2018-09-10 11:29:58 -07:00
Alex Crichton 70e4ed67ad signal: Touch up more impls and comments 2018-09-10 11:29:58 -07:00
Alex Crichton 699b9ab89e signal: Handle a few more errors 2018-09-10 11:29:57 -07:00
Alex Crichton ba0921a01d signal: Various cleanups:
* Drop nix/lazy_static
* Use previously registered handlers
* Handle some more errors
2018-09-10 11:29:57 -07:00
Michal 'vorner' Vaner 367cb56e02 signal: The driver task
Add the driver task, connecting the signal handler wakeups to the
wakeups of of the streams.

It is a prototype-quality code, a lot of cleanups and similar is needed.
2018-09-10 11:29:57 -07:00
Michal 'vorner' Vaner 04d949c380 signal: Provide the new kind of Signal stream
Which is just a wrapper around the futures::sync::mpsc. The sender is in
a global registry.

The part that connects the wakeups to the senders in the registry
doesn't yet exist.
2018-09-10 11:29:57 -07:00
Michal 'vorner' Vaner ed4359bb26 signal: Implement the wake-up part of the new signal handling
Register the signal handler that wakes up someone through a self-pipe.
That someone doesn't yet exist, though.

Some dependencies (nix, lazy_static) added to speed up the prototyping
process. They are likely to be dropped in some future commits.

Some features (eg. preserving the previous signal handlers) are still
missing.
2018-09-10 11:29:57 -07:00
Michal 'vorner' Vaner 4142dc2fae signal: Use tokio-core from git
Just for now, as we need some yet unreleased features.
2018-09-10 11:29:57 -07:00
Alex Crichton 468b037e4e signal: Update docs urls and such 2018-09-10 11:29:56 -07:00
Alex Crichton b33ae3cdd6 signal: Remove deprecated API usage on Windows 2018-09-10 11:29:56 -07:00
Alex Crichton 4519ac8e17 signal: Remove use of deprecated APIs on Unix 2018-09-10 11:29:56 -07:00
Alex Crichton 92b93ee176 signal: Bump to 0.1.1 2018-09-10 11:29:56 -07:00
Alex Crichton 635149e3ab signal: Ignore errors in signal handler
Closes alexcrichton/tokio-signal#3
2018-09-10 11:29:56 -07:00
Alex Crichton e28c350e31 signal: Update travis token 2018-09-10 11:29:56 -07:00
Chris Emerson 1a122018a2 signal: Trivial typo fix. 2018-09-10 11:29:55 -07:00
Alex Crichton f3f8ee431e signal: Remove SIGKILL reexport 2018-09-10 11:29:55 -07:00
Alex Crichton 61c4047c6a signal: Add symbolic reexports for common signals
Means you don't have to import libc!

Closes alexcrichton/tokio-signal#1
2018-09-10 11:29:55 -07:00
Alex Crichton 3486a61a0f signal: Update deps to point to crates.io 2018-09-10 11:29:55 -07:00
Alex Crichton 8291c3d462 signal: Start adding windows support 2018-09-10 11:29:55 -07:00
Alex Crichton 1b6893b6f6 signal: Track tokio-core master 2018-09-10 11:29:55 -07:00
Alex Crichton eca7f0760f signal: Initial commit 2018-09-10 11:29:50 -07:00
Ben Boeckel 89d969d518 StreamExt: add a trait for additional Stream methods (#573)
Primarily, it offers a `timeout` method for streams.
2018-09-07 15:43:03 -07:00
Carl Lerche 16664189c1 async-await: move examples into dedicated crate (#608)
This works around a bug in the cargo renaming feature as well as allows
the use of `[patch]` in the `Cargo.toml`.
2018-09-06 13:36:59 -04:00
Carl Lerche 6828870608 async-await: bump version to v0.1.2 (#619) 2018-09-04 15:02:15 -07:00
Nimi Wariboko Jr 89d0cda2e2 async-await: use new PinMut/PinBox location (#613)
The types moved in `std`. This patch updates tokio-async-await to
import `PinMut` and `PinBox` from the new location.

Ref: rust-lang/rust#53227
2018-09-04 13:19:10 -07:00
Stjepan Glavina 8052a9b348 guide: fix a few typos (#612) 2018-09-03 10:18:53 -07:00
ksqsf a5ac6c8b72 Fix undesired multi-line error message (#605) 2018-08-31 09:53:41 -07:00
Léo Gaspard 3a59526523 Document that timeout-ed futures will be polled at least once (#603)
tokio-util: document behavior of `StreamExt::timeout` when timeout = 0
2018-08-31 09:26:41 -04:00
Zachary Stewart 322a94f72f Update documentation for AsyncRead and AsyncWrite (#596)
tokio-io: update documentation for AsyncRead and AsyncWrite
2018-08-31 09:00:32 -04:00
Eunchong Yu c03b23355b Fix minimum version to export tokio::codec module (#594)
tokio-async-await: fix minimum version to export tokio::codec module (#594)
2018-08-31 08:02:02 -04:00
Eliza Weisman bc91bc5022 Fix non-terminating loop in tokio_io::length_delimited::FramedWrite (#576)
* tokio-io: fix non-terminating loop in length_delimited::FramedWrite (#497)
2018-08-31 06:31:43 -04:00
Flux Xu a7b053372f Add ThreadPool::spawn_handle (#602)
## Motivation

`tokio_threadpool::ThreadPool::spawn` has no return value.

## Solution

Add `ThreadPool::spawn_handle` which calls
`futures::sync::oneshot::spawn` to return a future represents the return
value.
2018-08-30 16:53:05 -07:00
Eliza Weisman 673fdb5cb3 Refactor codec::length_delimited (#575)
This patch refactors `length_delimited` to be implemented as a `Codec` and
use the default `Framed` wrapper types.

The original implementation did not do this in order to support vectored writes in the
write half. However, this implementation would be more efficient with small frames anyway.

If vectored writes are to be explored in the future, then it should be done holistically.

Signed-off-by: Eliza Weisman <[email protected]>
2018-08-30 14:50:32 -07:00
Carl Lerche 97618746de readme: fix section ordering (#600) 2018-08-30 14:46:40 -07:00
Carl Lerche d8f8b59df9 guide: add a testing section to the contributing guide (#598) 2018-08-30 12:26:24 -07:00
Jon Gjengset 0745a9b88a Use spawn_local to spawn from local Handles (#565)
Previously, every call to `current_thread::Handle::spawn` would go
through a `mpsc` channel. This is unnecessary when the `Handle` is still
on the same thread as the current thread executor. This patch fixes that
by storing the `ThreadId` of the executor when it is created, and then
comparing against that when `Handle::spawn` is called. If the call is
made from the same thread, `spawn_local` is used directly.

Fixes #562.
2018-08-30 11:24:59 -07:00
Eliza Weisman a7f5ba28ba Bump minimum supported version & document support policy (#599)
* Bump minimum supported version & document support policy

Signed-off-by: Eliza Weisman <[email protected]>
2018-08-29 20:35:27 -04:00
Josef Brandl cc3b6af7a3 Fix tokio-uds version (#580) 2018-08-28 15:12:45 -07:00
Martin Chaine 07e30ae923 net: rework tokio_tcp and tokio_udp re-exports (#548)
This patch keeps the primary net types in `tokio::net` and moves
secondary types to a protocol specific submodules.

Primary types are the ones that users are most likely to name (`TcpStream`,
`TcpListener`, `UdpSocket`, ...)

Secondary types are the operation futures.
2018-08-28 14:13:06 -07:00
Jason Davies 69d90ac7ee Fix a few typos in timer docs. (#569) 2018-08-28 11:00:42 -07:00
Carl Lerche d16032cf06 async-await: misc fixes and typos (#585) 2018-08-27 15:16:32 -07:00
Carl Lerche b479ce78d3 add experimental async/await support. (#582)
This patch adds experimental async/await support to Tokio. It does this
by adding feature flags to existing libs only where necessary in order
to add nightly specific code (mostly `Unpin` implementations). It then
provides a new crate: `tokio-async-await` which is a shim layer on top
of `tokio`.

The `tokio-async-await` crate is expected to look exactly like `tokio`
does, but with async / await support. This strategy reduces the amount
of cfg guarding in the main libraries.

This patch also adds `tokio-channel`, which is copied from futures-rs
0.1 and adds the necessary `Unpin` implementations. In general, futures
0.1 is mostly unmaintained, so it will make sense for Tokio to take over
maintainership of key components regardless of async / await support.
2018-08-27 12:24:51 -07:00
Michal 'vorner' Vaner 6e45e0ac61 re-export tokio-current-thread::spawn (#579)
Re-export it inside the tokio::runtime::current_thread, as the original
place (tokio::executor::current_thread) is hidden from documentation and
users need some way to spawn non-Send futures.
2018-08-25 12:51:49 -07:00
Ben Boeckel 82c5baa09b Spelling fixes (#571)
* docs: fix spelling and whitespace errors
2018-08-25 15:26:41 -04:00
Carl Lerche 7dc6404726 draft initial CONTRIBUTING guide (#567)
This guide was adopted from the node.js project.
2018-08-24 13:03:34 -07:00
Eliza Weisman 2e88e29fe9 Move tokio_io::codec::length_delimited module to tokio::codec (#568)
* Deprecate tokio-io::length_delimited
* Move `length_delimited` into `tokio::codec`

Signed-off-by: Eliza Weisman <[email protected]>
2018-08-24 15:54:42 -04:00
Carl Lerche 07203408de Bump version to v0.1.8 (#566)
This also bumps a number of sub crates:

* tokio-executor (0.1.3)
* tokio-io (0.1.8)
* tokio-reactor (0.1.4)
* tokio-threadpool (0.1.6)
* tokio-timer (0.2.6)
* tokio-udp (0.1.2)
2018-08-24 08:58:26 -07:00
Carl Lerche 8bf2e9aeb0 Introduce Timeout and deprecate Deadline. (#558)
This patch introduces `Timeout`. This new type allows setting a timeout
both using a duration and an instant. Given this overlap with
`Deadline`, `Deadline` is deprecated.

In addition to supporting future timeouts, the `Timeout` combinator is
able to provide timeout functionality to streams. It does this by
applying a duration based timeout to each item being yielded.

The main reason for introducing `Timeout` is that a deadline approach
does not work with streams. Since `Timeout` needed to be introduced
anyway, keeping `Deadline` around does not make sense.
2018-08-22 20:39:46 -07:00
Carl Lerche cf184eb326 timer: Reduce size of Delay struct (#554)
* Remove `counted` field on `timer::Entry`.

It turns out that a better indicator of whether or not the number of
active timeouts should be decremented is if the `Entry` has been
associated with a timer. In other words, if `Entry::inner` can be
upgraded, then the count should be decremented on drop.

* timer: Tweak link between `Delay` and the driver

This tweaks the struct layout / details regarding how a `Delay` instance
is linked to a driver (timer instance). Instead of lazily allocating the
`Entry` (node shared between `Delay` and the timer), `Entry` is
allocated immediately when `Delay` is created. This allows using the
entry store data used by `Delay`.

This is in anticipation of further timer improvements that would
otherwise require the size of `Delay` to grow further. Since an
allocation is already made, the idea is to shrink the size of the
`Delay` struct.
2018-08-21 21:48:40 -07:00
Carl Lerche d822b721b4 Add DelayQueue implementation to tokio-timer (#550)
This patch adds a `DelayQueue` to tokio_timer. The `DelayQueue` allows
inserting elements as well as specifying a time at which the element
should be returned to the user. This allows handling more complex
timeout situations.
2018-08-20 21:47:10 -07:00
Carl Lerche c66b56c3fb Implement Default for tokio_timer::Handle (#553)
This patch implements `Default` for `tokio_timer::Handle`. It returns a
`Handle` instance that is not bound to a specific timer. Instead, it
will use the timer for the current execution context. This is the same
strategy used by `tokio_reactor::Handle`.

Fixes #547
2018-08-20 13:01:39 -07:00
Carl Lerche 89639ec48b Bump tokio-uds version to v0.2.1 (#552)
Fixes #551
2018-08-19 21:23:49 -07:00
Martin Chaine 2b1b0ac858 Expose tokio_uds from the root crate (#526) 2018-08-15 21:26:10 -07:00
Carl Lerche 6b84c73f12 tokio::codec docs + additional exports (#546) 2018-08-15 21:25:25 -07:00
Jason Ish 767b370c21 Add tokio-tls echo example. (#541)
Based on the current example on the front page of tokio.rs.
2018-08-15 07:54:24 -04:00
Gary M. Josack 28010b5962 Update lines_encoder test to use LinesCodec (#544)
The `lines_encoder` test is a copy/paste of `bytes_encoder` and not
testing the LinesCodec encoding at all. This updates the test to do
simple validations of the LinesCodec encoding.
2018-08-15 07:51:42 -04:00
Roman 2e343f9e42 Reexport Encoder, Decoder, Framed* from tokio::codec (#499) 2018-08-14 11:18:54 -07:00
Mateusz Mikuła 31f71dedee Routine dependencies update (#533)
* Update dependencies

* Replace deprecated tempdir with tempfile
2018-08-10 12:37:45 -07:00
Stjepan Glavina 989262fe6e Enable sanitizer tests for tokio-threadpool (#537)
Closes #536.
2018-08-10 19:13:51 +02:00
Carl Lerche d91c775f36 Remove dead futures2 code. (#538)
The futures 0.2 crate is not intended for widespread usage. Also, the
futures team is exploring the compat shim route.

If futures 0.3 support is added to Tokio 0.1, then a different
integration route will be explored, making the current code unhelpful.
2018-08-09 21:56:53 -07:00
Stjepan Glavina 96b556fbff Steal multiple tasks from another worker at a time (#534)
* Steal multiple tasks from another worker at a time
* Better spinning and failing pop
* Update crossbeam-deque and simplify spinning
2018-08-09 12:14:13 -07:00
Stjepan Glavina fd36054ae4 Use a scalable RW lock in tokio-reactor (#517) 2018-08-09 11:23:45 -07:00
Carl Lerche 89d6bfc5cb Bump tokio-tls to v0.2.0 (#531)
This prepares the crate for release.
2018-08-08 10:17:28 -07:00
David Kellum decc83e959 Update to crossbeam-utils 0.5.0, fix imports (#519) 2018-08-08 08:57:25 -07:00
Sean McArthur afcfefd7e3 Move tokio-tls into workspace (#529) 2018-08-08 08:36:17 -07:00
Roman c89b0b4c8c Fix num CPUs in threadpool::builder::Builder::new (#530)
Closes #400
2018-08-08 08:33:01 -07:00
Stjepan Glavina 6b1e4ab0a3 Implement Error for a few error types (#511) 2018-08-07 19:45:58 -07:00
David Kellum 4153cc4076 Fix more rustdoc links (#518)
* Fix a cut-paste error with -reactor rustdoc links
* Fix more ::reactor rustdoc broken links
* Minor rustdoc typo
* Consistently reference std::io::{Read, Write} in rustdoc/links
2018-08-07 19:45:39 -07:00
Serho Liu 5304557d1d Fix tokio threadpool readme examples (#521) 2018-08-07 19:44:45 -07:00
Andrew Cann fdb2f61357 Udp socket readiness methods (#522) 2018-08-07 19:41:27 -07:00
Carl Lerche e964c4136c Bump subcrate versions (#524)
* tokio-current-thread 0.1.1
* tokio-executor 0.1.3
* tokio-fs 0.1.3
* tokio-reactor 0.1.3
* tokio-tcp 0.1.1
* tokio-timer 0.2.5
2018-08-06 20:36:50 -07:00
Brian Olsen 0490280d66 tokio-fs: Add async versions of most of std::fs (#494)
* create_dir
* create_dir_all
* hard_link
* read_dir
* read_link
* remove_dir
* remove_file
* rename
* set_permissions that works with path
* symlink_metadata
* symlink on unix
* symlink_dir on windows
* symlink_file on windows
2018-07-31 21:39:27 -07:00
Sam Rijs 0f76470172 detect and handle recursive calls to DefaultExecutor (#473) 2018-07-30 20:59:08 -07:00
Stjepan Glavina 9352249c3e Terminate backup threads when idle (#489) 2018-07-30 20:48:53 -07:00
Stjepan Glavina e5b2681513 Fix a race in thread wakeup (#507) 2018-07-30 20:46:46 -07:00
Stjepan Glavina 629c9f0698 Small fixes (#508)
* Make Shutdown public
* Remove unused import
* Fix documentation mistake
* Fix typo
2018-07-30 20:46:04 -07:00
Alan Somers 5d0d2a2e12 Ignore tokio-uds's test_socket_pair on FreeBSD. (#493)
It requires FreeBSD 12.0 or later.  Also, fix a spelling mistake in a
comment.
2018-07-24 14:00:01 -07:00
kohensu ad4693a18f Fix the doc of read_to_end method (#482) 2018-07-24 13:57:15 -07:00
Laurențiu Nicola c85bde3170 tokio: expose tokio_fs::metadata (#479) 2018-07-24 13:56:42 -07:00
Jon Gjengset 1e90e27720 Count in-transit spawned futures to current thread executor as pending (#478) 2018-07-24 13:49:01 -07:00
Carl Lerche f212a2ab9d Fix Weak tsan whitelist (#505) 2018-07-24 13:37:48 -07:00
Michal 'vorner' Vaner 84db325628 RunError and few more error types implements Error (#501)
This allows them to be used with things like `failure`.
2018-07-24 13:27:57 -07:00
Douman 365efec24a Add Interval::interval shortcut for a better usability (#492) 2018-07-23 23:08:49 -07:00
David Kellum 491f15827b General rustdoc improvements (#450)
* Normalize links to docs.rs/CRATE/M.N/...

docs.rs is smart enough to show docs for the latest M.N.P release when
M.N is used in the link. For example:

  https://docs.rs/mio/0.6/mio/struct.Poll.html

..will show mio 0.6.14 and later docs. While using the `M.N.*`
(ASTERISK) syntax also works, `M.N` is the more common usage, so
standarize a few existing links to that format.

* Fix missing or malformed rustdoc links

* executor lib rustdoc minor format change

* Promote tokio-threadpool crate level comments to rustdoc

* Replace hidden tokio::executor::thread_pool docs with deprecation note

* Fix typo/simplify util module rustdoc

* Reuse some tokio::executor::thread_pool rustdoc for the crate

Relates to #421
2018-07-22 13:35:30 -07:00
Stjepan Glavina c17ecb53e7 Pad fields to cacheline size to avoid false sharing (#475) 2018-07-16 14:22:48 -07:00
Jon Gjengset 6ba8e7621d Add free block_on_all in current thread Runtime (#477) 2018-07-11 15:32:58 -07:00
Laurențiu Nicola 39c95d6206 tokio-fs: Bump version to 0.1.2 (#469)
* Add a couple of missing full stops in the documentation
2018-07-11 15:09:37 -07:00
Sam Rijs 78b6bd4ca5 implement Send and Sync for DefaultExecutor (#472)
Fxes #376
2018-07-11 12:35:32 -07:00
Richard Dodd (dodj) b3ff9e315c Update lib.rs (#471)
Fix build failure on nightly (combination of warning for "cannot be resolved" and lint deny(warnings))
2018-07-11 12:30:51 -07:00
Stjepan Glavina 990186ec9d Optimize spinning in Worker::run (#470) 2018-07-11 12:30:26 -07:00
Stjepan Glavina 19da6ff59a New version of crossbeam-deque (#468) 2018-07-11 12:24:10 -07:00
Roman 36c817f0c3 Update rand dep from 0.4 to 0.5 (#458) 2018-07-11 12:14:40 -07:00
David Kellum 35123f7ae4 Additional details for tokio-fs rustdoc (#454) 2018-07-11 12:13:16 -07:00
João Oliveira 54b7c1b10d tokio-tcp: add tokio::net::TcpStream::try_clone (#448) 2018-07-11 11:54:08 -07:00
Patrick Barrett e6fc3d209d return NotReady when recv_from wouldblock in uds (#452) 2018-07-11 11:37:57 -07:00
Carl Lerche f98b81e527 Bump minimum supported Rust to 1.25. (#465)
Currenty, 1.27 is the latest released Rust version.
2018-07-06 14:14:05 -07:00
Stjepan Glavina dc7202cfa9 Replace XorShiftRng with a custom RNG (#466) 2018-07-06 13:33:52 -07:00
Carl Lerche f1a7caea3f Bump tokio-threadpool to v0.1.5 (#462) 2018-07-05 10:22:03 -07:00
Stjepan Glavina b019532bc2 Implement status() for DefaultExecutor (#463) 2018-07-05 10:19:49 -07:00
Stjepan Glavina 7fb579c667 Fix a race in thread wakeup (#459) 2018-07-03 16:28:50 -07:00
Stjepan Glavina dbefa67058 Make WorkerId public (#460) 2018-07-02 13:34:08 -07:00
Roman 24d99c029e Add a verbose error message for BlockingError (#451)
Add a verbose error message for EnterError while trying to run
tokio_threadpool::blocking on a current_thread::Runtime
2018-06-26 08:37:48 -07:00
Laurențiu Nicola 3fecd0154c Add an explicit wait for the test to finish (#445) 2018-06-22 14:07:02 -07:00
Laurențiu Nicola 0440343a11 tokio-fs: add changelog for 0.1.2 (#444) 2018-06-22 14:06:50 -07:00
Roman 3cf56b7bfa Fix unneeded mut and some deprecated api (#442) 2018-06-21 09:47:21 -07:00
Roman 7153d8d6ce Add a verbose error message for EnterError (#441)
Add a verbose error message for EnterError while trying to run an
executor while another executor is already running.

Fixes: #410
2018-06-21 09:46:45 -07:00
Laurențiu Nicola ecfe2f6a05 tokio-fs: add tokio_fs::File::seek (#434) 2018-06-21 09:43:35 -07:00
Laurențiu Nicola 5753553ba3 Move metadata to a submodule (#439) 2018-06-21 09:41:38 -07:00
Laurențiu Nicola 04a4bfd455 tokio-fs: add tokio_fs::metadata (#433) 2018-06-20 13:12:06 -07:00
Jake Goulding b2f77dcebe Add a dedicated Future for retrieving the metadata of a file (#385) 2018-06-18 16:00:43 -07:00
Carl Lerche 85cf47de86 Enable backtraces in CI & disable TSAN (#436)
This PR enables backtraces when running tests and disables tsan for the thread pool.

The thread sanitizer was generating too many false positives. Once #329 lands, then it can
be re-enabled.
2018-06-18 15:15:45 -07:00
Steven Fackler 45bcea6c4f Reexport tokio_uds::ConnectFuture (#430) 2018-06-18 13:26:06 -07:00
Carl Lerche 3fac7ce68c Add some thread pool docs (#421) 2018-06-15 15:20:25 -07:00
Marc-Antoine Perennou 71c8f561e3 runtime: add block_on_all (#398)
Signed-off-by: Marc-Antoine Perennou <[email protected]>
2018-06-14 22:13:39 -07:00
Sean McArthur 011ebf44eb Implement Executor for Box<E: Executor> (#420) 2018-06-14 16:28:23 -07:00
Carl Lerche c25ea78ec9 Bump version of a number of sub crates (#414)
This includes:

* tokio-codec (0.1.0)
* tokio-current-thread (0.1.0)
* tokio-fs (0.1.1)
* tokio-io (0.1.7)
* tokio-reactor (0.1.2)
* tokio-udp (0.1.1)
2018-06-13 10:24:56 -07:00
Carl Lerche 2e0cd292d2 Fix some broken doc links (#413) 2018-06-13 09:02:46 -07:00
Sylwek 4ebaf18c27 Typo (#415) 2018-06-13 09:02:34 -07:00
Carl Lerche ab07733d66 Deprecate executor re-exports (#412) 2018-06-12 14:41:12 -07:00
Mat Sadler d1f825ca13 Add OpenOptions to tokio-fs (#390)
Add an `OpenOptions` struct to `tokio-fs` that mirrors the one found in
`std`. Also provide a conversion from a `std` instance to a Tokio instance.
2018-06-12 10:47:24 -07:00
Laurențiu Nicola 4cf7d73b22 tokio-fs: add into_std (#403) 2018-06-12 10:40:43 -07:00
jpbriquet 2cd854c2c7 tokio-current-thread crate (#370)
Extract `tokio::executor::current_thread` to a tokio-current-thread
crate. Deprecated fns stay in the old location. The new crate only
contains thee most recent API.
2018-06-12 10:26:03 -07:00
Carl Lerche ba05c39d65 Fix a deadlock that can happen when shutting down (#409)
There is a deadlock that can occur when the concurrent runtime shuts
down. This patch adds a test and fix.

Fixes #401.
2018-06-12 09:41:18 -07:00
Alyssa Ross 64b8884911 Fix typo in comment (#402) 2018-06-11 15:26:55 -07:00
pravic d391e63418 Duplicated word in documentation. (#405) 2018-06-11 15:17:09 -07:00
Carl Lerche 8d8c895a1c Remove tokio-codec dependency from tokio (#397)
This will be added again later once types are re-exported.
2018-06-08 09:56:40 -07:00
Carl Lerche dba5c27296 Bump version to v0.1.7 (#396)
This also bumps the versions of:

* tokio-threadpool
* tokio-timer
2018-06-06 20:14:35 -07:00
Carl Lerche db620b42ec Another attempt at abstracting Instant::now (#381)
Currently, the timer uses a `Now` trait to abstract the source of time.
This allows time to be mocked out. However, the current implementation
has a number of limitations as represented by #288 and #296.

The main issues are that `Now` requires `&mut self` which prevents a
value from being easily used in a concurrent environment. Also, when
wanting to write code that is abstract over the source of time, generics
get out of hand.

This patch provides an alternate solution. A new type, `Clock` is
provided which defaults to `Instant::now` as the source of time, but
allows configuring the actual source using a new iteration of the `Now`
trait. This time, `Now` is `Send + Sync + 'static`. Internally, `Clock`
stores the now value in an `Arc<Now>` value, which introduces dynamism
and allows `Clock` values to be cloned and be `Sync`.

Also, the current clock can be set for the current execution context
using the `with_default` pattern.

Because using the `Instant::now` will be the most common case by far, it
is special cased in order to avoid the need to allocate an `Arc` and use
dynamic dispatch.
2018-06-06 16:04:39 -07:00
David Kellum 9013ed9bd4 Fix description of BlockingError as io::Error (#384) 2018-06-06 14:34:55 -07:00
Carl Lerche 06325fa63b Bump tokio-uds to v0.2.0 (#395) 2018-06-06 14:09:07 -07:00
Sebastian Dröge 0d41ba7a08 Implement a Send Handle for the single-threaded Runtime (#340)
Implement a Send'able Handle for the single-threaded `Runtime` and
`CurrentThread` executor to spawn new tasks from other threads.
2018-06-05 16:56:15 -07:00
Carl Lerche c07a7b26d3 Cleanup FramedParts in new tokio-codec (#394) 2018-06-05 15:31:01 -07:00
Bryan Burgers f723d10087 Create tokio-codec (#360)
Create a new tokio-codec crate with many of the contents of
`tokio_io::codec`.
2018-06-04 20:36:06 -07:00
Jon Gjengset 3d7263d3a0 Implement Runtime::block_on using oneshot (#391) 2018-06-04 20:09:17 -07:00
Carl Lerche 9caec1c15d Remove futures2 crate (#380) 2018-05-29 16:28:00 -07:00
Carl Lerche 703f07ca17 Remove threadpool disclaimer (#378) 2018-05-29 15:59:37 -07:00
Michal 'vorner' Vaner db9371126d Include a manually built runtime example (#306) 2018-05-29 14:44:28 -07:00
Carl Lerche eb1cf8fc9b Unpin Rust nightly version (#379) 2018-05-29 14:36:52 -07:00
Carl Lerche 4af6109398 Fix bug related to spawning optimization (#375)
The thread pool optimizes cases where a task currently running on the
pool spawns a new future. However, the optimization did not factor in
cases where two thread pools interacted.

This patch fixes the optimization and includes a test.

Fixes #342
2018-05-24 22:06:32 -07:00
Roman Zeyde 96f3ec903c Fix a small typo in README.md (#373) 2018-05-23 12:07:46 -07:00
Chris Pick 8c791fd0bf Fix Runtime::new's doc link to tokio::run (#371) 2018-05-22 15:29:15 -07:00
Rijenkii c0747a5fc1 tokio-io: Fix the link to the repository (#372) 2018-05-22 15:28:28 -07:00
Carl Lerche c8e710d39e Import tokio-uds (#365)
This imports tokio-uds from the dedicated repo.
2018-05-14 14:48:32 -07:00
Carl Lerche e281e4f4cb Remove fuchsia references as it is not supported. (#355) 2018-05-14 12:00:19 -07:00
Carl Lerche 6598334021 Add Gitter badge to README (#358) 2018-05-14 12:00:10 -07:00
main() 35f3351c97 Document Handle::default() behavior (#359) 2018-05-14 11:11:28 -07:00
Jason Davies 1f5bb121e2 Fix typo in doc comment. (#361) 2018-05-14 11:10:25 -07:00
sbstp 88801bb613 timer: add sleep free function (#347) 2018-05-11 09:16:08 -07:00
Carl Lerche a850063211 Handle::default() should lazily bind to reactor. (#350)
Currently, not specifying a `Handle` is different than using
`Handle::default()`. This is because `Handle::default()` will
immediately bind to the reactor for the current context vs. not
specifying a `Handle`, which binds to a reactor when it is polled.

This patch changes the `Handle::default()` behavior, bringing it inline
with actual defaults.

`Handle::current()` still immediately binds to the current reactor.

Fixes #307
2018-05-11 08:32:03 -07:00
Marek Kotewicz 14ec268b8a Fixed broken link in tokio-fs documentation (#352) 2018-05-11 08:31:06 -07:00
Thijs Vermeir 363b207f2b Fix typo in documentation (#346) 2018-05-08 11:44:50 -07:00
Julian Tescher 06b2c40222 Fix typos (#348) 2018-05-08 11:44:17 -07:00
Thijs Vermeir 68b82f5721 Fix typo in documentation (#341) 2018-05-04 07:06:47 -07:00
Thijs Vermeir 7cca6499a9 Fix typo in documentation (#338) 2018-05-03 10:28:48 -07:00
Carl Lerche 8235eefbf0 Fix some dependency versions (#337) 2018-05-02 13:12:33 -07:00
Carl Lerche 14b31bdba5 Bump version to v0.1.6 (#336) 2018-05-02 12:14:44 -07:00
Carl Lerche f768163982 Filesystem manipulation APIs. (#323)
This patch adds a new crate: tokio-fs. This crate provides a wrapper
around `std` functionality that can only be performed using blocking
operations. This primarily includes filesystem operations, but it also
includes standard input, output, and error access as these streams
cannot be safely switched to non-blocking mode in a portable way.

These wrappers call the `std` functions from within a `blocking`
annotation which allows the runtime to compensate for the fact that the
thread will potentially remain blocked in a system call.
2018-05-02 11:19:58 -07:00
Carl Lerche 7a2b5db15c Remove futures2 feature from Cargo.toml files (#334)
Currently, the state of the futures2 integration is pretty broken. This
patch removes the feature flag, preventing users from trying to use it.
In the future, it can be brought back when the implementation is fixed.
2018-05-02 10:48:58 -07:00
Roman 2465483845 Current thread runtime (#308)
This patch introduces a version of `Runtime` that runs all components on
the current thread. This allows users to spawn futures that do not implement
`Send`.
2018-05-02 09:40:42 -07:00
Stefan Bühler 6a0ecef81a Timer: always park nested Park (#327)
The nested `Park` might need to do some work, even if the duration is 0
seconds (e.g. a `Reactor`).

Similar to what #313 did for CurrentThread.
2018-05-01 16:33:41 -07:00
Stefan Bühler 6defeeb2ba current_thread: make underlying Park instance accessible 2018-05-01 14:33:38 -07:00
Stefan Bühler b36a73059d tokio-io: require bytes-0.4.7 for Buf::get_uint_be 2018-05-01 14:33:38 -07:00
Roman d1d4fe4d07 Stop using deprecated bytes APIs in tests (#324) (#331) 2018-04-30 10:02:48 -07:00
Carl Lerche 9aaa8f06d1 Stop using deprecated bytes APIs (#324)
This also adds a filter for another treiber stack expected data race. The
race is expected as part of the algorithm.
2018-04-28 12:25:22 -07:00
Sebastian Dröge 6ea00162b9 Make CurrentThread::turn() more fair by always parking with 0 timeout… (#313)
This ensures that all fd-based futures are put into the queue for the
current tick, if the CurrentThread is parking via the Reactor.

Otherwise, if there are queued up futures already, only those would be
polled in the turn. These futures could then notify others/themselves to
have the queue still non-empty on the next turn. Which then potentially
allows the reactor to never be polled, and thus fd-based futures are
never queued up and polled.

Also return in the Turn return value whether any futures were polled at
all, which allows the caller to know if any work was done at all in this
turn and based on that adjust behavior.
2018-04-25 10:37:18 -07:00
Carl Lerche 61d635e8ad Threadpool blocking (#317)
This patch adds a `blocking` to `tokio-threadpool`. This function serves
as a way to annotate sections of code that will perform blocking
operations. This informs the thread pool that an additional thread needs
to be spawned to replace the current thread, which will no longer be
able to process the work queue.
2018-04-15 12:29:22 -07:00
Carl Lerche 372400ed34 Add additional timer::Error docs. (#311)
Closes #302
2018-04-10 14:28:37 -07:00
Roman ba9d849ef0 Fix warning: variable does not need to be mutable (#309) 2018-04-10 13:33:05 -07:00
Roman 5b677934fe Add example that prints each packet from tcp client (#301) 2018-04-10 13:08:55 -07:00
Sam Rijs dbcd8353b0 Update futures2 to use the futures 0.2 release (#304) 2018-04-08 20:23:33 -07:00
Carl Lerche 3be6b69e1b Refactor threadpool task types (#300)
Replaces homegrown Arc with std Arc

Is this safer? Unknown. At least we don't have to maintain an arc
implementation anymore. This will also make it easier to filter out tsan
false positives.

Also split task/mod.rs into multiple files.
2018-04-05 10:57:05 -07:00
Carl Lerche 0bcf9b0ae6 ThreadPool refactoring (#299) 2018-04-04 13:30:54 -07:00
Carl Lerche c715739599 Add arc::Weak to tsan filter. (#298) 2018-04-04 12:54:49 -07:00
David 6aea9c43e8 Update Cargo.toml (#293) 2018-04-04 09:18:56 -07:00
Igor Gnatenko 82f6a52d1a threadpool: bump minimal version of executor (#292) 2018-04-04 09:18:40 -07:00
Leandro Pacheco a6b307cfbe re-export io::{ReadHalf/WriteHalf} timer::Error (#290) 2018-04-04 09:18:12 -07:00
Roman dcb20b289c Build 32/64-bit Linux and FreeBSD on Travis CI (#286) 2018-04-04 08:37:28 -07:00
Carl Lerche 79afc7ee68 Threadpool refactor (#294)
* Switch worker lifecycle to an enum
* Move some files around
* Rename State -> PoolState
2018-04-03 22:35:59 -07:00
Kam Y. Tse 3ba5595233 Fix typo (#275) 2018-04-02 13:11:06 -07:00
Carl Lerche 7232ba6d55 Bump tokio-timer to v0.2.1 (#287) 2018-04-02 11:06:22 -07:00
Roman a14de909eb Build both x86 and x64 on Windows (#282) 2018-04-02 09:37:56 -07:00
laizy d8789cd379 fix panic in chat example (#279) 2018-04-02 09:00:40 -07:00
Roman 8d4be0361e Fix unused variable in tokio-threadpool\tests\threadpool.rs:581:9 (#284) 2018-04-02 09:00:14 -07:00
Daniel Griffen 3f2710397d Fix tokio-timer on 32bit systems (#274) 2018-04-02 08:53:43 -07:00
Roman 8895a7d3ab Fix Appveyor badge on crates.io page (#280) 2018-04-01 16:16:22 -07:00
Carl Lerche 10cb9dd468 Actually bump tokio to v0.1.5 (#273) 2018-03-30 15:37:52 -07:00
Carl Lerche 2ca214bd2c Fix tokio dependency versions (#272) 2018-03-30 15:32:25 -07:00
Carl Lerche 2a01c26d58 Bump version to v0.1.5 (#271)
This also bumps:

* tokio-executor to v0.1.2
* tokio-threadpool to v0.1.2
* tokio-timer to v0.2.0
2018-03-30 15:28:44 -07:00
Carl Lerche ea172537aa Rename Sleep to Delay (#270)
This patch renames `Sleep` from tokio-timer and the tokio facade to
`Delay`. Given that the future does not actually put anything to sleep,
the `Delay` name feels more appropriate.

Fixes #263
2018-03-30 14:21:48 -07:00
Carl Lerche baa2502ec6 Integrate timers with runtime. (#266)
This patch integrate the new timer implementation with the runtime by
initializing a timer per worker thread. This allows minimizing the
amount of synchronization needed for using timers.
2018-03-30 11:50:02 -07:00
Carl Lerche d4d17392fe Remove println from tests (#267) 2018-03-29 20:58:02 -07:00
Carl Lerche 6807363efd Fix permissions (#268) 2018-03-29 20:42:59 -07:00
Carl Lerche 1c5d131245 Allow customizing the threadpool's parker (#264)
* Allow customizing the threadpool's parker

This patch allows the user of threadpool to customize how the worker
threads park themselves. This allows custom parking logic to be
injected. For example, this allows embedding a timer on each worker
thread.

* Call `park` instance every so often.

Since the `park` is now customizable, it might have logic that must be
called every so often. For example, a timer might have timeouts that it
must expire.

Currently, if a worker is very busy, it won't call into the `park`
instance. This patch changes this so that after every 32 task
invocations, `park` is called with a duration of zero.
2018-03-29 13:47:08 -07:00
Carl Lerche 19500f7df8 Provide a timer implementation (#249)
This patch adds a new crate: tokio-timer. This crate provides an
efficient timer implemeentation designed for use in Tokio based
applications.

The timer users a hierarchical hashed timer wheel algorithm with six
levels, each having 64 slots. This allows the timer to have a resolution
of 1ms while maintaining O(1) complexity for insert, removal, and firing
of timeouts.

There already exists a tokio-timer crate. This is a complete rewrite
which solves the outstanding problems with the existing tokio-timer
library.

Closes #146.
2018-03-28 22:26:47 -07:00
Roman ad189826f4 Split tokio-threadpool lib.rs into files (#233)
* Builder -> src/builder.rs
* Callback -> src/callback.rs
* Config -> src/config.rs
* Futures2Wake -> src/futures2_wake.rs
* Inner -> src/inner.rs
* Notifier-> src/notifier.rs
* Sender -> src/sender.rs
* Shutdown -> src/shutdown.rs
* ShutdownTask -> src/shutdown_task.rs
* SleepStack -> src/sleep_stack.rs
* State -> src/state.rs
* ThreadPool -> src/thread_pool.rs
* Worker -> src/worker.rs
* WorkerEntry -> src/worker_entry.rs
* WorkerState -> src/worker_state.rs
2018-03-27 15:56:21 -07:00
Klaus Purer a612736f54 fix(cargo): Bump dependencies so that Tokio compiles with minimal versions (#258) 2018-03-27 15:47:11 -07:00
Carl Lerche bda8dd5113 Update futures2 Cargo.toml (#256) 2018-03-27 15:46:19 -07:00
Sam Rijs 415a786049 Fix unstable-futures feature flag propagation (#261) 2018-03-27 15:46:02 -07:00
Carl Lerche 2edc35a45d Disable future 0.2 tests (#259) 2018-03-24 14:01:41 -07:00
Carl Lerche 9cffda59c9 Bump version to v0.1.4 (#252)
This also bumps:

* tokio-executor: v0.1.1
* tokio-reactor: v0.1.1
* tokio-threadpool: v0.1.1
2018-03-23 10:34:42 -07:00
Carl Lerche 23d95b44e7 Change hammer test consts (#255) 2018-03-23 10:27:58 -07:00
Denis 69e45f4be4 Fix a typo in tokio_reactor::PollEvented (#250)
`read_readiness` -> `write_readiness` in *write* methods
2018-03-22 20:15:31 -07:00
Denis 6bdfa159a7 Fix connect example for UDP (#241)
Close #241
2018-03-22 10:02:01 -07:00
Michal 'vorner' Vaner 5d87a9cee1 Docs: warn about errors from TcpListener::incoming (#247) 2018-03-22 10:01:05 -07:00
Denis 16d3540ce9 Add UDP client example (send/recv_dgram) (#239) 2018-03-22 10:00:27 -07:00
Sean McArthur e5ebd02885 implement poll_vectored_* and initializer method for futures2 (#242) 2018-03-22 09:59:13 -07:00
Carl Lerche 08c21e7bac Fix race condition related bugs (#243)
* Fix races.

This mostly pulls in changes from rust-lang-nursery/futures-rs#881, but
also updates Registration to be a bit more obvious as to what is going
on.

* Reduce spurious wakeups caused by Reactor

This patch adds an ABA guard on token values before registering them
with Mio. This allows catching token reuse and avoid the notification.

This is needed for OS X as the notification is used to determine that a
TCP connect has completed. A spurious notification can potentially cause
write failures.
2018-03-22 09:57:40 -07:00
Aaron Turon 8786741ba9 Update to futures 0.2.0-beta (#246) 2018-03-21 14:21:02 -07:00
Roman 494f0dc176 Runtime builder (#234)
* Split runtime module into files
* Add runtime::Builder to set up thread pool.
2018-03-21 11:23:36 -07:00
Cyril Plisko df9025594c Lapsus clavis (#245) 2018-03-21 11:17:16 -07:00
Aaron Turon 7b1306e6c2 Add top-level tests for futures 0.2 integration (#231) 2018-03-15 16:38:12 -07:00
Sean McArthur b7f4e337be set Runtime thread pool name prefix (#232) 2018-03-15 16:37:32 -07:00
Hiroaki Nakamura d1046db735 Fix condition for updating the current date buffer (#230) 2018-03-15 09:29:55 -07:00
Sam Rijs 923a80e098 Move tokio::net module into tokio tcp/udp crates (#224) 2018-03-14 09:38:59 -07:00
Carl Lerche 64435f5b35 Travis: Move before_deploy out of matrix block (#229) 2018-03-13 15:58:53 -07:00
Aaron Turon d304791c0e Simultaneous futures compat (#172)
This patch adds opt-in support for futures 0.2.
2018-03-13 13:57:35 -07:00
Carl Lerche 5846b3fc2a Reduce AtomicTask spurious notifications (#227) 2018-03-13 13:28:41 -07:00
Carl Lerche 8eb3e58b7d Shutdown the runtime on drop (#214)
Currently, the runtime does not shutdown if the runtime handle is
dropped. This can happen during a panic or when the value is simply
dropped.

This patch forces the runtime to shutdown if it is not explicitly
shutdown.

Fixes #209
2018-03-13 13:14:51 -07:00
Carl Lerche c0a2cc1f9e Add LICENSE file to all sub crates (#226)
* Add LICENSE file to all sub crates
* Update links in README
2018-03-13 13:14:28 -07:00
Carl Lerche 61b2889881 Try compiling Tokio on FreeBSD (#228) 2018-03-13 13:14:12 -07:00
hcpl 5dab821b29 Fix docs markup (#225) 2018-03-13 11:43:05 -07:00
Wesley Moore 2abeff01a5 Fix build on FreeBSD (#218) 2018-03-13 11:24:17 -07:00
Carl Lerche 96a542451d Handle futures that panic on a threadpool (#216)
If a future panics from within the context of a thread pool, the pool
should not be impacted. To do this, polling the future is wrapped with a
catch_unwind. Extra care is taken to ensure that `thread::panicking()`
is set from within the future's drop handle.

Fixes #209
2018-03-13 09:44:14 -07:00
Gray Olson 95899e007d Update comment in udp-codec example (#222) 2018-03-12 10:39:32 -07:00
Jeehoon Kang e6e3c49e0e Remove uses of futures_cpupool (#220) 2018-03-11 11:37:10 -07:00
Carl Lerche 4d514b7eb3 Relicense Tokio exclusively under the MIT license. (#215)
This patch relicenses the Tokio project exclusively under the MIT
license. Before this, the project was dual licensed under MIT and Apache
2. As such, switching to only MIT is permitted.

Fixes #202
2018-03-09 20:07:09 -08:00
Tosil Velkov 2a1585157e Fix wrong file link in examples readme.md (#208) 2018-03-09 12:26:09 -08:00
Igor Gnatenko 189d6baac4 tokio-threadpool: bump rand to 0.4 (#205) 2018-03-09 12:25:38 -08:00
Igor Gnatenko 3ad27e99ec tokio-reactor: bump mio to 0.6.14 (#204)
With 0.6.13 it doesn't compile:
no method named `as_usize` found for type `mio::Ready` in the current scope
2018-03-09 12:25:16 -08:00
Carl Lerche bf1305c421 Bump version to v0.1.3 (#213) 2018-03-09 11:41:31 -08:00
Carl Lerche cf7435ba30 CurrentThread::turn should block on idle. (#212)
This patch fixes a bug where `CurrentThread::turn` is expected to block
even if the executor is idle.

The `turn` API is the low level interface for callers to interact with
the `Sleep` instance used by the `CurrentThread` instance. As such, a
call to `turn` is expected to call `sleep` once if the executor did not
perform any work.
2018-03-09 11:09:10 -08:00
Carl Lerche e18c23afa1 Bump tokio to v0.1.2 (#201)
This also bumps tokio-io to v0.1.6 and prepares for the initial release
of tokio-executor, tokio-reactor, and tokio-threadpool.
2018-03-08 20:15:51 -08:00
Carl Lerche bb9de276ae Add an explicit spawn fn to TaskExecutor (#200) 2018-03-08 14:54:31 -08:00
Carl Lerche fed4d72eff Improve the chat example, making it more robust (#199)
This handles cases where clients send large amounts of data while on
localhost.

Closes #192
2018-03-08 13:38:52 -08:00
Carl Lerche 142bd3b2a9 Depend on latest release of Mio (#198) 2018-03-08 13:36:54 -08:00
Jake Goulding 7da5603a42 Remove premature French translation of "current" (#197) 2018-03-08 08:48:46 -08:00
Carl Lerche 264fef60e3 Update readme (#196) 2018-03-07 22:28:01 -08:00
Carl Lerche 25dd54d263 Improve poll_read_ready implementation (#193)
This patch updates `poll_read_ready` to take a `mask` argument, enabling
the caller to specify the desired readiness. `need_read` is renamed to
`clear_read_ready` and also takes a mask.

This enables a caller to listen for HUP events without requiring reading
from the I/O resource.
2018-03-07 16:24:51 -08:00
Carl Lerche 5555cbc85e Shutdown the thread pool on drop. (#190)
Currently, if a thread pool instance is dropped without being shutdown,
the workers will run indefinitely. This is not ideal as it leaks the
threadpool.

This patch forces the thread pool to shutdown on drop.

Closes #151
2018-03-06 21:33:45 -08:00
Carl Lerche c769b915b7 Explicitly deregister I/O resources on drop (#189)
Mio will be requiring `deregister` to be called explicitly in order to
guarantee that Poll releases any state associated with the I/O resource.
See carllerche/mio#753.

This patch adds an explicit `deregister` function to `Registration` and
updates `PollEvented` to call this function on drop.

`Registration::deregister` is also called on `PollEvented::into_inner`.

Closes #168
2018-03-06 14:40:20 -08:00
Carl Lerche 1f91a890b4 Fix benches (#188)
Some of the benchhmarks were broken and/or using deprecated APIs. This
patch updates the benches and requires them all to compile without
warnings in order to pass CI.
2018-03-06 14:40:09 -08:00
Carl Lerche 869615f1d2 Fix some comments in the examples. (#187)
The PR that updated the examples skipped some comments. This patch
updates thhe comments.
2018-03-06 12:00:49 -08:00
Colin Rofls ae20270d00 Fixup docs for AllowStdIo (#184) 2018-03-06 10:41:24 -08:00
Carl Lerche f1cb12e14f Update examples to track latest Tokio changes (#180)
The exampes included in the repository have lagged behind the changes
made. Specifically, they do not use the new runtime construct.

This patch updates examples to use the latest features of Tokio.
2018-03-06 09:59:04 -08:00
Roman 56c5797872 Split net::udp code into files: (#183)
- UdpSocket -> src/net/udp/socket.rs
- SendDgram -> src/net/udp/send_dgram.rs
- RecvDgram -> src/net/udp/recv_dgram.rs
2018-03-06 09:53:23 -08:00
Jeehoon Kang aa4b1b4311 Replace coco with crossbeam (#185) 2018-03-06 09:49:01 -08:00
Roman 687871d3e5 Split net::tcp code into files: (#177)
- Incoming -> src/net/tcp/incoming.rs
- TcpListener -> src/net/tcp/listener.rs
- TcpStream, ConnectFuture -> src/net/tcp/stream.rs
2018-03-05 12:44:09 -08:00
Philip Munksgaard 071d8704ce Fix typos (#176) 2018-03-05 11:12:43 -08:00
Carl Lerche 9f7a98af3c Switch TCP/UDP fns to poll_ -> Poll<...> style (#175)
Tokio is moving away from using `WouldBlock`, instead favoring
`Async::NotReady`.

This patch updates the TCP and UDP types, deprecating any function that
returns `WouldBlock` and adding a poll_ prefixed equivalent.
2018-03-04 10:46:54 -08:00
Carl Lerche 7db7719419 Tweak the tokio::spawn function (#171)
Currently, `tokio::spawn` matched the `spawn` function from futures 0.2.
However, this adds additional ergonomic overhead and removes the ability
to spawn from a drop fn. See rust-lang-nursery/futures-rs#830.

This patch switches the behavior to access the thread-local variable
referencing the default executor directly in the `spawn` function.
2018-03-02 15:45:35 -08:00
Carl Lerche 21c0f3a9d8 Add AsyncRead::poll_read, AsyncWrite::poll_write. (#170)
This removes the need for the `try_nb` macro as well as bring the traits
closer in line with the planed 0.2 iteration.
2018-03-02 15:15:05 -08:00
Carl Lerche e1b3085153 Extract the reactor to a dedicated crate. (#169)
This allows libraries that require access to reactor related types to
depend on this crate without having to depend on the entirety of Tokio.

For example, libraries that implement their custom I/O resource will
need to access `Registration` or `PollEvented`.
2018-03-02 13:51:34 -08:00
Carl Lerche df6e24255b Fix deprecation warnings in tests (#167) 2018-03-01 21:50:07 -08:00
Carl Lerche df19119c0a Add io facade and update reactor docs (#166)
This patch updates the documentation for a number of APIs. It also
introduces a prelude module and an io facade module, re-exporting types
from tokio-io.
2018-03-01 21:48:18 -08:00
Carl Lerche 164ee8f106 Update the README (#164) 2018-02-28 15:03:45 -08:00
Carl Lerche 7238cfa5e2 Update AppVeyor badge URL (#163) 2018-02-28 13:48:08 -08:00
Carl Lerche 7de749b77b Provide a handle to Runtime's executor. (#162)
Sometimes, passing ownership to an executor is necessary. For example,
some libraries require taking ownership of one.

This patch adds a function that returns an executor associated with a
runtime.
2018-02-28 09:07:14 -08:00
Carl Lerche 2eabc37599 I/O resources lazily bind to reactor. (#160)
This patch makes a significant change to how I/O resources bind to a
reactor. Currently, an I/O resource (TCP, UDP, PollEvented) will bind
itself with a reactor upon creation.

First, some history.

Originally, tokio-core required that I/O resources be explicitly
associated with a reactor upon creation by passing in a `&Handle`. Tokio
reform introduced a default reactor. If I/O resources do not specify a
reactor upon creation, then the default reactor is used.

However, futures tend to favor being lazy. Creating a future should do
no work, instead it is defining a computation to be performed once the
future is executed. Binding an I/O resource with a reactor on creation
goes against this pattern.

This patch fixes this by allowing I/O resources to lazily bind to a
reactor. An explicit `&Handle` can still be used on creation, but if no
reactor is specified, then the default reactor is used. However, this
binding happens during execution time (read / write) and not creation.
2018-02-28 09:03:13 -08:00
Roman 1190176be7 Improve current thread tests (#161)
* Create variables as closer as possible to their usage
* Check that no message is lost in test current_thread::hammer_turn
2018-02-28 09:00:25 -08:00
Carl Lerche 8e1a9101f0 Support current_thread::spawn from task drop (#157)
Currently, the thread-local tracking the current thread executor is not
set when a task is dropped. This means that one cannot spawn a new
future from within the drop implementation of another future.

This patch adds support for this by setting the thread-local before
releasing a task.

This implementation is a bit messy. It probably could be cleaned up, but
this is being put off in favor of trying a more comprehensive
reorganization once the current thread executor is feature complete.
2018-02-27 09:56:29 -08:00
Roman 427b7325d0 Update badges in README (#159) 2018-02-27 09:35:50 -08:00
Carl Lerche 2961a2388c Fix race condition in CurrentThread. (#156)
The logic that enables `CurrentThread::turn` to avoid unbounded
iteration was incorrect. It was possible for unfortunate timing to
result in a dead lock.

This patch provides a fix as well as a test.
2018-02-26 20:41:06 -08:00
Carl Lerche df3a92532b Only deploy docs on linux. Take 2 (#155)
Try using an env var to enforce the doc deploy condition.
2018-02-26 14:50:07 -08:00
Carl Lerche 23f451e8b1 Only deploy docs on linux (#154) 2018-02-26 14:12:41 -08:00
Ben Boeckel 40cbd0f296 length_delimited: add a native_endian builder method (#144)
This method is useful when reading from a operating system service.
2018-02-26 10:38:56 -08:00
Alan Somers 3b64fe9363 Lio3 (#142)
FreeBSD uses a separate kqueue filter type for lio_listio.  This change
adds support for that filter type.  Full functionality will be provided
by the mio-aio and tokio-file crates.

* Add PollEvented::into_inner

Consumes a PollEvented and returns its inner io object.  Useful for io
types that have exclusive ownership of a resource.

See also https://github.com/tokio-rs/tokio-core/commit/9400ffb
2018-02-26 09:39:57 -08:00
Carl Lerche 5334de5e44 Fix bug with CurrentThread::turn (#152)
CurrentThread::turn uses a turn count strategy to allow `turn` to not
run infinitely. Currently, there is a bug where spawned tasks will not
get executed in calls to `turn`.

This patch fixes the bug by correctly setting the turn count for newly
spawned tasks.
2018-02-23 22:15:46 -08:00
Carl Lerche fe14e7b127 Introduce the Tokio runtime: Reactor + Threadpool (#141)
This patch is an intial implementation of the Tokio runtime. The Tokio
runtime provides an out of the box configuration for running I/O heavy
asynchronous applications.

As of now, the Tokio runtime is a combination of a work-stealing thread
pool as well as a background reactor to drive I/O resources.

This patch also includes tokio-executor, a hopefully short lived crate
that is based on the futures 0.2 executor RFC.

* Implement `Park` for `Reactor`

This enables the reactor to be used as the thread parker for executors.
This also adds an `Error` component to `Park`. With this change, a
`Reactor` and a `CurrentThread` can be combined to achieve the
capabilities of tokio-core.
2018-02-21 07:42:22 -08:00
Carl Lerche e0d95aa037 Update root license file 2018-02-20 15:13:52 -08:00
cetra3 dc225faf24 Adjust handle documentation (#140) 2018-02-14 14:23:39 -08:00
Roman 8605d5d243 Make benches compilable again (#133) 2018-02-13 10:02:06 -08:00
Carl Lerche 4704f61277 Remove references to Remote (#135)
Fixes #121
2018-02-12 14:13:11 -08:00
Roman 88a7030f73 Split io code (#129)
* move src/io.rs -> src/io/mod.rs
* move src/read.rs -> src/io/read.rs
* move src/read_exact.rs -> src/io/read_exact.rs
* move src/read_until.rs -> src/io/read_until.rs
* move src/read_to_end.rs -> src/io/read_to_end.rs
* move src/flush.rs -> src/io/flush.rs
* move src/copy.rs -> src/io/copy.rs
* move src/shutdown.rs -> src/io/shutdown.rs
* move src/write_all.rs -> src/io/write_all.rs
* move Async{Read,Write} => src/io/async_{read,write}.rs
* move Async{Read,Write} => src/async_{read,write}.rs
2018-02-12 09:52:05 -08:00
Roman 35aeabd3ff Split codec code (#128)
* move src/codec.rs -> src/codec/mod.rs
* Move traits Encoder and Decoder from src/framed_{read|write}.rs into src/codec/{encoder,decoder}.rs
* Move LinesCodec and BytesCodec from src/codecs.rs into src/codec/{lines,bytes}_codec.rs
2018-02-12 09:10:19 -08:00
Carl Lerche 0b58bded7c Bump version to v0.1.1 (#131) 2018-02-09 14:30:32 -08:00
Carl Lerche 609786ed41 Remove fn that was never intended to be pub (#130)
This function could not be called from a public setting in the first
place due to the argument types being private.
2018-02-09 11:32:38 -08:00
Carl Lerche a9da59882c Fix example doc comment (#124)
Fixes #123
2018-02-08 09:09:02 -08:00
Carl Lerche 4ae76132c1 Update the required Mio point release. (#120)
Tokio depends on the latest Mio point release, so update Cargo.toml to
reflect this.
2018-02-07 14:45:12 -08:00
Carl Lerche 23bc9d20d3 Prepare for tokio 0.1 release (#119) 2018-02-07 13:28:29 -08:00
Carl Lerche c225b46b18 Make Handle::wakeup private (#117)
The `Handle` type is intended to be used by end users of Tokio. The
wakeup functionlity is needed by executor implementations. It doesn't
make sense to put executor specific functionality on a type that is
intended for end users.
2018-02-07 11:09:44 -08:00
Carl Lerche c30fa62dda Remove framed fn from UdpSocket (#116)
Instead, use `UdpFramed::new` to create a framed wrapper around the UDP
socket.
2018-02-07 10:42:27 -08:00
Roman ad8338e4da Remove UdpCodec (#109)
`UdpFramed` is updated to use the `Encoder` and
`Decoder` traits from `tokio-io`.
2018-02-06 13:41:31 -08:00
cssivision 73b763f69f Fix: struct shoutdown ignore Async::NotReady (#114) 2018-02-06 13:30:05 -08:00
Carl Lerche f0ea9d6f4c Switch back to futures from crates.io (#113)
Doing so requires copying the `current_thread` executor from GitHub into
the repo.
2018-02-06 07:26:21 -08:00
Carl Lerche 567887cc75 Add a chat example (#112) 2018-02-05 20:45:12 -08:00
Roman 3840ceafee Rename TcpStreamNew -> ConnectFuture (#111) 2018-02-05 20:09:00 -08:00
Carl Lerche a5e9c311bf Fix link to documentation in README (#108) 2018-02-02 13:46:15 -08:00
Carl Lerche 2e94b658ed Track futures tokio-reform branch (#88)
This patch also updates tests and examples to remove deprecated API
usage.
2018-02-01 10:31:07 -08:00
Carl Lerche b9db119b45 Move tokio-io into the git repository. (#96)
The crates remain separate, but are now developed in the same git
repository using cargo workspaces.

This facilitates making coordinated changes.
2018-01-31 21:06:42 -08:00
Carl Lerche a87936080b Limit the max number of registered resources (#95)
* Limit the max number of registered resources

This allows some token space to be used internally. Also, Mio 0.7 will
be limiting the token space some as well.

Mio: https://github.com/carllerche/mio/issues/788

Closes #42
2018-01-31 20:09:44 -08:00
Carl Lerche 65cbfced29 Poll evented mutability (#37)
Generally speaking, it is unsafe to access to perform asynchronous
operations using `&self`. Taking `&self` allows usage from a `Sync`
context, which has unexpected results.

Taking `&mut self` to perform these operations prevents using these
asynchronous values from across tasks (unless they are wrapped in
`RefCell` or `Mutex`.
2018-01-31 20:09:15 -08:00
Carl Lerche a616220090 Move set_fallback to Reactor from Handle. (#93)
The caller should be required to have control of a reactor when setting
it as a fallback. A `Handle` is used to pass into libraries and
functions and should not grant capability of using the associated
reactor as a fallback.

Closes #71
2018-01-31 12:39:47 -08:00
Carl Lerche a998367002 Add CHANGELOG stub. 2018-01-30 13:27:12 -08:00
Carl Lerche c1c06f8ac1 Remove UDP only_v6 accessors. (#94)
These fns are not included on std's UdpSocket.
2018-01-30 15:26:02 -06:00
Carl Lerche ae627db266 Change net::Incoming signature to match std. (#89)
std's `Incoming` iterator yields `TcpStream` instances. This patch
updates the `Incoming` future to match this signature.

This changes the yielded value from `(TcpStream, SocketAddr)` ->
`TcpStream`.
2018-01-30 15:01:34 -06:00
Carl Lerche f4ec9a6360 Remove only_v6 from TCP types (#90) 2018-01-30 14:59:23 -06:00
Carl Lerche 0f4706d752 Update send_dgram function signature. (#91)
* Update send_dgram function signature.

All other fns take `&SocketAddr`.

* Fix tests
2018-01-30 14:49:55 -06:00
Carl Lerche 117dcba8cb Remove &addr arg from TcpListener::from_std (#92)
This has been deprecated in mio.
2018-01-30 14:49:32 -06:00
Carl Lerche fd37fb0f17 Merge remote-tracking branch 'core/master' into new-crate 2018-01-26 14:50:41 -08:00
Carl Lerche a41c0800f9 Uncomment deny(warnings) 2018-01-26 10:12:19 -08:00
Sean McArthur e140dabed2 Use 64 iovecs in TcpStream::write_buf (#295) 2018-01-26 09:17:44 -08:00
Alex Crichton fbdf04f604 More OSX fixes 2018-01-25 07:32:55 -08:00
Alex Crichton a3c4aec127 Fix compile on OSX 2018-01-22 08:14:05 -08:00
Alex Crichton 730228c8cb Add debug logs for how long dispatch takes (#81)
I've often found this to be quite useful when debugging why event loops are
stuck or some other bug looks to be in play.
2018-01-18 13:00:53 -06:00
Alex Crichton 826e27685c Delete the IoToken type (#83)
This was added oh-so-long ago and nowadays is just used by one consumer,
`PollEvented`. Let's just inline the already small implementation directly into
`PollEvented` which should make it easier to modify in the future as well
2018-01-18 10:48:59 -08:00
Roman 025f52aadc Fix UdpCodec::encode (#85)
*     Refactor UDP SendDgram & RecvDgram

    Get rid of unnamed structs in the favor of private structs with named fields

*     Change the signature of UdpCodec::encode

    Now it is:

    ```
        fn encode(&mut self, msg: Self::Out, buf: &mut Vec<u8>) -> Result<SocketAddr, Self::Error>;
    ```

    Closes https://github.com/tokio-rs/tokio/issues/79

* Fix compilation error from `mio` crate
2018-01-16 08:49:59 -08:00
Michal 'vorner' Vaner b081e9593f Get rid of some deprecated warnings (#292)
And allow the others to pass.
2018-01-13 12:03:30 -06:00
Alex Crichton 99fc38e0d6 Bump to 0.1.12 2018-01-08 09:51:05 -08:00
Sean McArthur ce014943ec add TcpStream::peek (#291) 2018-01-08 11:34:33 -06:00
Alex Crichton dac13c1df4 Use an events iterator rather than indexing (#82)
Eventually mio won't provide an indexable interface, so switch over to using the
iterator-based interface for now.
2018-01-05 08:47:01 -08:00
Alex Crichton 555c97b313 Expand CI coverage and update README (#80)
Closes #64
2018-01-05 08:43:37 -08:00
Bastien Orivel b395ccb6d9 Bump dependencies (#289) 2018-01-02 12:03:54 -06:00
Sean Stangl 943cd860cb Use correct project name in README.md. (#288) 2018-01-02 12:03:18 -06:00
Alex Crichton cde387d7e7 Touch up documentation for Reactor::turn 2017-12-19 14:18:28 -08:00
dethoter 9303076a6b Change a return value of reactor::poll to io::Result. (#40)
* Change a return value of reactor::poll to io::Result.

* Revert "Change a return value of reactor::poll to io::Result."

This reverts commit 281d8c32d4.

* Return a result from reactor::poll.

* Drop a reactor if any error occurs. Fix warnings in tests.

* Update a documentation for reactor::turn.

* Unwrap the last turn() call in tests.
2017-12-19 16:15:30 -06:00
Alex Crichton 571e322755 Return a Turn type from the turn method (#60)
This is mostly just future-proofing, the type doesn't actually do anything right
now.
2017-12-13 13:25:20 -06:00
Alex Crichton 4ef772b2db Remove Handle argument from I/O constructors (#61)
This commit removes the `Handle` argument from the following constructors

* `TcpListener::bind`
* `TcpStream::connect`
* `UdpSocket::bind`

The `Handle` argument remains on the various `*_std` constructors as they're
more low-level, but this otherwise is intended to set forth a precedent of by
default not taking `Handle` arguments and instead relying on the global
`Handle::default` return value when necesary.
2017-12-12 18:32:50 -06:00
Alex Crichton 849771ecfa Add a Handle::wakeup method (#59)
This method is intended to be used to wake up the reactor from a remote thread
if necessary, forcing it to return from a blocked call of `turn` or otherwise
prevent the next call to `turn` to from blocking.
2017-12-12 15:19:39 -06:00
Alex Crichton a577bfc033 Remove the Reactor::run method (#58)
This commit removes the `Reactor::run` method which has previously been used to
execute futures and turn the reactor at the same time. The tests/examples made
heavy usage of this method but they have now all temporarily moved to `wait()`
until the futures dependency is upgraded. In the meantime this'll allow us to
further trim down the `Reactor` APIs to their final state.
2017-12-11 21:29:18 -06:00
Alex Crichton 32f2750c2d Start adding a global event loop
This commit starts to add support for a global event loop by adding a
`Handle::default` method and implementing it. Currently the support is quite
rudimentary and doesn't support features such as shutdown, overriding the return
value of `Handle::default`, etc. Those will come as future commits.
2017-12-11 17:26:39 -06:00
Carl Lerche c45bbaa04e Bump to v0.1.11 2017-12-11 13:58:30 -06:00
Steven Fackler 963eee3bc7 Add TcpListener::accept_std (#284) 2017-12-07 20:00:49 -06:00
Thomas de Zeeuw 23a0e990d2 return TcpStreamNew for TcpStream::connect_std (#66) 2017-12-06 14:59:57 -06:00
Thomas de Zeeuw 402cd3034d Avoid allocation when return a WouldBlock io::Error (#65) 2017-12-06 10:32:58 -06:00
Thomas de Zeeuw cf793d4053 Derive debug on public structs (#62)
* Derive Debug on all public structs

* Enable a warning about missing debug implementations on public struct
2017-12-06 10:19:21 -06:00
Alex Crichton 108e1a2c1a Blanket rename Core to Reactor
This commit uses a script to rename `Core` to `Reactor` all at once, notably:

    find . -name '*.rs' | xargs sed -i 's/\bCore\b/Reactor/g'
2017-12-05 09:02:07 -08:00
Alex Crichton 46062794aa Tweak the PollEvented::deregister signature
This commit changes the `PollEvented::deregister` signature from

    fn deregister(self, handle: &Handle) -> io::Result<()>

to

    fn deregister(&self) -> io::Result<()>

Now that the handles are `Send` and `Sync` there's no longer any need to pass it
in (it's already stored in the `PollEvented` itself). Additionally this switches
to `&self` instead of `self` to allow reclamation of the internal resources if
necessary.
2017-12-05 08:54:48 -08:00
Alex Crichton 2e58422890 Add TcpListener::accept_std as a method
This should allow configuration over what reactor accepted streams go on to by
giving back a libstd-bound object that can then be used later in conjunction
with `TcpStream::from_std`.
2017-12-05 08:48:17 -08:00
Alex Crichton e86fc4917a Change need_read and need_write to return an error
This commit is targeted at solving tokio-rs/tokio-core#12 and incorporates the
solution from tokio-rs/tokio-core#17. Namely the `need_read` and `need_write`
functions on `PollEvented` now return an error when the connected reactor has
gone away and the task cannot be blocked. This will typically naturally
translate to errors being returned by various connected I/O objects and should
help tear down the world in a clean-ish fashion.
2017-12-05 08:43:01 -08:00
Alex Crichton 8fcce957cd Rename networking constructors with _std
This commit renames the various constructors of networking types to have a
`_std` suffix instead of a smorgasboard of other suffixes, canonicalizing on
`_std` as the suffix for constructors which take the libstd corresponding types.
2017-12-05 08:24:26 -08:00
Alex Crichton 259996d805 Remove NEXT_LOOP_ID
This is no longer needed now that the public-facing `CoreId` has been removed
2017-12-05 08:19:47 -08:00
Alex Crichton 329bca15a6 Remove TcpListener::pending_accept field
No need for oneshot shenanigans as now we'll always have the `Handle` available
to us regardless of what thread we're on to associate a new socket
2017-12-05 08:17:08 -08:00
Alex Crichton 7c768fc046 Remove the Remote type
The `Handle` type is now `Send` and `Sync` so the `Remote` type no longer needs
to exist.
2017-12-05 08:15:26 -08:00
Thomas de Zeeuw c801584d24 Doc improvements (#46)
* small doc cleanups in PollEvented

* small doc cleanups in IoToken

* improve crate level documentation

- Add links to the futures, mio and tokio-uds crates.
- Add links to various structs and types mentioned.
- use eprintln for error reporting in the example.

* improvements to the UdpSocket documentation

- Fixed links usage.
- Removed references to a no longer existing `Window` struct.
- Made notes about using functions in context of a future.

* documentation improvements to UdpFramed and UdpCodec

- Since HTTP uses TCP (QUIC aside) using it as an example in an UDP
protocol feels wrong.
- Make the note of tampering with the underlying streams more explicit.

* update reactor module level documentation

Adds an explanation of every public struct.

* expand Handle and Remote documentation

* expand net module documentation

Adds an explanation of every public struct and how they work together.

* update TcpListener documentation

Reorder the various option methods; get first then set.
Note about panicing added to poll_read.

* remove mention of none-existing future R

* improve documentation of TcpStream

* fix UdpSocket doc

This when wrong when merging various commits.
2017-12-05 09:55:25 -06:00
Thomas de Zeeuw 0b54557796 Remove unused code (#44)
* remove unused #[macro_use] and #[allow(unused_macros)]

* remove unused FnBox trait

* remove unused temporary variable

* remove Evented trait requirement to implement Debug
2017-12-01 15:34:03 -06:00
Alex Crichton b7ff130a0d Tweak travis config 2017-11-30 18:44:36 -08:00
dethoter 31f8cb9467 Remove Core:id. (#41) 2017-11-21 10:18:11 -08:00
Carl Lerche 4c268a8939 Make Handle Send + Sync. (#35)
* Make Handle `Send + Sync`.

This is an initial implementation making `Handle: Send + Sync`. It uses
a `RwLock` to coordinate access to the underlying state storage. An
implementation without the lock is left to later.

This pass also leaves a lot of dead code that can be removed in later
commits.

* Remove reactor code related to message passing

The previous commit removed the need for using message passing to
communicate with the reactor. This commit removes all the unnecessary
code.
2017-11-17 12:51:23 -08:00
Alex Crichton 701488e6a1 Merge pull request #279 from asomers/futures
bump futures to 0.1.16
2017-11-17 14:14:11 +01:00
Alan Somers 2764fc3de2 bump futures to 0.1.16
examples/tinydb.rs uses futures::prelude, which was added in 0.1.16
2017-11-16 22:42:36 -07:00
Carl Lerche 9c16d47632 Merge remote-tracking branch 'core/master' into new-crate 2017-11-06 23:30:10 -08:00
Carl Lerche a402b1ca1e Run CI on Travis (#31)
Mio should be providing the compatibility layer so there is no need to
run CI on OS X as well as Linux.

Benches are currently being skipped as the Tokio reform work progresses.
2017-11-06 23:08:14 -08:00
Alex Crichton 1fe55b2b55 Don't unwrap accepted connections
Helps avoid spurious errors when testing.

Closes #277
2017-11-06 08:23:11 -08:00
Alex Crichton 6cca729f40 Merge pull request #30 from seamusabshere/patch-1
s/serde/tokio/ in README license section
2017-11-02 16:26:46 -04:00
Seamus Abshere 2ab2affe69 s/serde/tokio/ 2017-11-02 16:01:42 -04:00
Carl Lerche 8c838a2709 Merge pull request #20 from tokio-rs/remove-scheduler
Remove executor from reactor.
2017-11-01 07:38:27 -07:00
Carl Lerche c6f1ff13d2 Remove executor from reactor.
In accordance with tokio-rs/tokio-rfcs#3, the executor functionality of
Tokio is being removed and will be relocated into futures-rs as a
"current thread" executor.

This PR removes task execution from the code base. As a temporary
mesure, all examples and tests are switched to using CpuPool.

Depends on #19.
2017-11-01 07:28:49 -07:00
Carl Lerche 697851210c Remove timers from Tokio.
In accordance with tokio-rs/tokio-rfcs#3, timers are being extracted
from Tokio and moved to a separate crate (probably futures-timer).

This PR removes timers from the code base.
2017-10-30 18:16:00 -07:00
Carl Lerche b23a997cb8 Remove deprecated code.
This commit removes code that was deprecated in tokio-core master.
2017-10-30 16:37:15 -07:00
Carl Lerche 36aaaa1520 Rename crate to tokio 2017-10-30 16:37:00 -07:00
Alex Crichton 25f30c91c4 Clarify wording of license information in README.
This text historically was copied verbatim from rust-lang/rust's own README [1]
with the intention of licensing projects the same as rustc's own license, namely
a dual MIT/Apache-2.0 license. The clause about "various BSD-like licenses"
isn't actually correct for almost all projects other than rust-lang/rust and
the wording around "both" was slightly ambiguous.

This commit updates the wording to match more precisely what's in the
standard library [2], namely clarifying that there aren't any BSD-like licenses
in this repository and that the source is licensable under either license, at
your own discretion.

[1]: https://github.com/rust-lang/rust/tree/f0fe716dbcbf2363ab8f929325d32a17e51039d0#license
[2]: https://github.com/rust-lang/rust/blob/f0fe716dbcbf2363ab8f929325d32a17e51039d0/src/libstd/lib.rs#L5-L9
2017-10-30 14:17:01 -07:00
Alex Crichton 0c5c5dfafe Merge pull request #271 from cramertj/simplify-udp
Simplify UdpSocket futures
2017-10-27 22:36:14 -04:00
Taylor Cramer 3588f4d6ad Simplify UdpSocket futures 2017-10-27 10:10:55 -07:00
Alex Crichton ca8104ad69 Merge pull request #272 from cramertj/must-use
Set Future types as must_use
2017-10-27 12:19:21 -04:00
Alex Crichton 39173f8830 Merge pull request #270 from cramertj/fix-warnings
Fix warnings
2017-10-27 11:36:38 -04:00
Taylor Cramer 7624061021 Set Sink types as must_use 2017-10-25 18:03:31 -07:00
Taylor Cramer bd9a07f3ad Set Stream types as must_use 2017-10-25 18:02:14 -07:00
Taylor Cramer b4fa47bd09 Set Future types as must_use 2017-10-25 17:57:25 -07:00
Taylor Cramer 6b8ad4ff99 Fix warnings 2017-10-25 17:27:24 -07:00
Alex Crichton 01198532c1 Merge pull request #263 from casey/timeout-debug
Derive Debug for Timeout and TimeoutToken
2017-10-10 13:59:02 -04:00
Casey Rodarmor e10de1e94e Derive Debug for Timeout and TimeoutToken 2017-10-09 20:16:38 -07:00
Alex Crichton 335c3e73a4 Fix UDP test 2017-10-05 19:57:36 -07:00
Alex Crichton 1c88b8f336 Bump to 0.1.10 2017-10-05 10:47:57 -07:00
Alex Crichton 84916f66fd Take &SocketAddr in connect 2017-10-05 10:47:57 -07:00
Alex Crichton 259c7a0884 Make poll_at private again
Unsure that we'll want to continue to expose this, stick to being conservative
for now.
2017-10-05 10:46:51 -07:00
Alex Crichton 25760609fa Avoid 0-length IoVec instances
These are unsound on Windows (unfortunately) and will soon be disallowed due to
carllerche/iovec#5
2017-10-05 10:41:05 -07:00
Alex Crichton 0868b97832 Add a tinydb example sharing state
This example is intended to showcase sharing state between all connected clients
on a server, for example a key/value store (in-memory database)

Closes #257
2017-09-23 12:22:34 -07:00
Alex Crichton fbd0a9e5f1 Merge pull request #258 from alex/patch-1
Fixed docs for Timeout::new and new_at
2017-09-22 11:54:03 -05:00
Alex Gaynor 24dd856cfd Fixed docs for Timeout::new and new_at
They no longer return futures, they return io::Result.
2017-09-22 11:01:34 -04:00
Alex Crichton e33155edb1 Merge pull request #255 from mathstuf/doc-typos
docs: fix some typos
2017-09-14 15:36:20 -05:00
Ben Boeckel de33e02c01 docs: fix some typos 2017-09-14 16:19:45 -04:00
Alex Crichton 317c11552c Merge pull request #254 from alexcrichton/poll-at
Add {Interval,Timeout}::poll_at
2017-09-13 20:43:48 -05:00
Alex Crichton fb05eb34af Merge pull request #253 from alexcrichton/perf
Conditionally call `consume_queue` on messages
2017-09-13 16:33:26 -05:00
Alex Crichton 25dcb1fab5 Add {Interval,Timeout}::poll_at
Some contexts, like EC2, have `Instant::now` as a relatively expensive function
to call. To help amortize the cost of this function this commit exposes a new
function on `Interval` and `Timeout` to pass in the assumed current time.
2017-09-12 22:55:58 -07:00
Alex Crichton 97d80296cb Conditionally call consume_queue on messages
The `consume_queue` function can be relatively slow for an empty queue (the fast
path) so optimize this a bit with a preflight check that should just touch a few
atomics.
2017-09-12 21:42:22 -07:00
Alex Crichton b320d9ee58 Move timer heap assertions behind a dedicated cfg
No need to punish projects that enable debug assertions for themselves
2017-09-12 10:58:41 -07:00
Alex Crichton 63d7be0368 Merge pull request #251 from bkchr/udpsocket_connect
Adds UdpSocket connect, send and recv methods
2017-09-12 09:27:24 -05:00
Bastian Köcher 7950b43505 Adds a test for UdpSocket connect, recv and send 2017-09-12 14:37:40 +02:00
Bastian Köcher c80105fe1e Adds UdpSocket connect, send and recv methods 2017-09-12 14:00:55 +02:00
Alex Crichton 8a43472b35 Add an example of compressing on a CPU pool 2017-09-11 14:41:15 -07:00
Alex Crichton ecedea3404 Add a README for the examples 2017-09-11 13:31:08 -07:00
Alex Crichton 2e5cd1640e Merge pull request #250 from henninglive/udp-zero-length
UDP 0-length datagrams
2017-09-11 10:43:40 -05:00
Alex Crichton 85257e19af Touch up a few examples 2017-09-11 08:43:11 -07:00
Alex Crichton a611f6ec30 Add a UDP mode to the connect example 2017-09-11 08:33:09 -07:00
Henning Ottesen bda6ed9241 UDP 0-length datagrams
Resolves #248, preventing UdpFramed from sending 0-length datagrams.
Also, adds 0-length tests for UdpSocket.
2017-09-11 17:32:37 +02:00
Alex Crichton 5e4cfdfab1 Recommend the connect example over nc 2017-09-11 08:07:38 -07:00
Alex Crichton e0b751b013 Relax exact interval tests
Should make this more resilient to rounding errors on Windows
2017-09-11 07:44:32 -07:00
Alex Crichton 5e92b10f3f Add a "tiny" HTTP example
Hopefully being relatively illustrative in how a bare-bones non-production-ready
server can be spun up!
2017-09-10 21:45:23 -07:00
Alex Crichton a4e947fba0 Make timeout tests slightly more flexible 2017-09-10 19:58:35 -07:00
Alex Crichton 7b94cf307d Add a multithreaded echo server example 2017-09-10 08:54:35 -07:00
Alex Crichton 645ae7051d Merge pull request #247 from twmb/timeout_token_doc
TokenTimeout: add doc around new panic
2017-09-09 14:21:30 -05:00
Travis Bischel b9dc4c9008 TokenTimeout: add doc around new panic
My slab bump in #246 added a potential new panic in Core's Inner's
`cancel_timeout`.

Thankfully, the only way `cancel_timeout` can be called is from
TimeoutToken's `cancel_timeout`, which is crate-internal only and is
only called from Timeout's and Interval's drop fn's.

This change simply adds new clarifying documentation around
TokenTimeout's cancel_timeout to "future proof" anybody looking to use
cancel_timeout directly (not just on drop).
2017-09-08 22:31:37 -07:00
Alex Crichton e30b182147 Merge pull request #246 from twmb/bump_slab
bump slab to 0.4.0
2017-09-08 09:01:38 -05:00
Travis Bischel fce59de79e bump slab to 0.4.0
Makes some of the code easier to read.
2017-09-07 20:53:54 -07:00
Alex Crichton 04eba12d43 Merge pull request #244 from arthurprs/errorkind
Prefer ErrorKind::WouldBlock
2017-09-03 16:00:13 -05:00
arthurprs f12b761b77 Prefer ErrorKind::WouldBlock 2017-09-03 18:39:04 +02:00
Alex Crichton e8617ea1fc Update futures dependency 2017-08-24 08:16:04 -07:00
Alex Crichton 77d9a1aa4f Merge pull request #226 from Ralith/udp-dual-stack
Expose only_v6 option for UDP sockets
2017-08-17 13:05:31 -07:00
Alex Crichton 6090e22135 Merge pull request #238 from cssivision/master
update example in doc comment
2017-08-16 09:04:34 -07:00
cssivision e5fdccfff0 update example in doc comment 2017-08-16 19:17:12 +08:00
Alex Crichton fbd257f2bd Merge pull request #237 from raphlinus/master
[fuchsia] Config changes to build on Fuchsia
2017-07-31 18:59:12 -05:00
Raph Levien 05b1ba4342 [fuchsia] Config changes to build on Fuchsia
This patch disables various Unix-specific platform features that are
not enabled on Fuchsia. It also updates the mio version to 0.6.10,
which is the first release that supports Fuchsia.
2017-07-31 14:12:53 -07:00
Alex Crichton 77b0ee0a47 Hide the deprecated io module 2017-07-30 20:49:09 -07:00
Alex Crichton 2a71ef8b13 Merge pull request #236 from manuels/patch-1
Add documentation about panics to {Handle, Remote}::spawn{fn}
2017-07-26 11:57:24 -05:00
manuels d03c736b4c Add documentation about panics to {Handle, Remote}::spawn{fn} 2017-07-26 17:33:09 +02:00
Alex Crichton 8c297a6208 Bump to 0.1.9 2017-07-24 21:36:19 -07:00
Alex Crichton 8fba4858ac Merge pull request #231 from guanqun/master
typo fix in io_token's comment section
2017-07-12 09:07:23 -05:00
Guanqun Lu 5fe7b4225f typo fix in io_token's comment section 2017-07-12 13:21:54 +08:00
Alex Crichton c13e7f3533 Clarify docs on Timeout::reset 2017-06-27 09:55:36 -07:00
Alex Crichton 2653a2195c Merge pull request #228 from en/reset
Add a method to reset Timeout.
2017-06-27 09:52:02 -07:00
Yuanchao Sun 6fb62d3232 Add a method to reset Timeout. 2017-06-27 11:34:56 +08:00
Benjamin Saunders 8004900ce9 Expose only_v6 option for UDP sockets 2017-06-25 22:56:52 -07:00
Alex Crichton 8379b87c53 Merge pull request #224 from seanmonstar/nop-flush
make TcpStream::flush() a noop
2017-06-23 18:12:52 -05:00
Sean McArthur bf93b79120 make TcpStream::flush() a noop 2017-06-23 15:25:25 -07:00
Alex Crichton d85f54dffb Merge pull request #219 from ignatenkobrain/patch-1
bump env_logger to 0.4
2017-06-16 09:10:23 -05:00
Igor Gnatenko ddb244429e bump env_logger to 0.4 2017-06-16 08:41:09 +02:00
Alex Crichton c65c331767 Merge pull request #210 from asomers/aio5
POSIX AIO support, try 2
2017-06-08 14:30:22 -05:00
Alan Somers 363e15f36c Respond to alexchrichton's comments
* Combine the FreeBSD/Dragonfly platform with the other Unix platform
* Remove the Windows platform::aio method
* Update deps
2017-06-07 22:36:32 -06:00
Alex Crichton 562aa65c99 Bump to 0.1.8 2017-06-07 13:29:14 -07:00
Alex Crichton 74670f287e Merge pull request #215 from tokio-rs/benchmarks
TCP reactor benchmarks
2017-05-30 16:00:30 -05:00
Carl Lerche 9cd80f1cbd TCP reactor benchmarks 2017-05-30 11:23:34 -07:00
Alex Crichton d23c1a2b98 Merge pull request #214 from alexcrichton/futures-next
Update tokio-core with new task system
2017-05-30 10:43:19 -05:00
Alex Crichton 16d15520ad Update tokio-core with new task system 2017-05-30 08:42:32 -07:00
Alex Crichton 0be8eab260 Merge pull request #213 from tokio-rs/tcp-sock-opts
Expose TCP socket options
2017-05-27 12:19:08 -05:00
Carl Lerche 7acffe4785 Expose TCP socket options 2017-05-27 09:37:25 -07:00
Alan Somers 42f73cb0ec Revert changes to read_ready and add platform::all() 2017-05-21 11:01:48 -06:00
Alan Somers 81beb44565 POSIX AIO support, try 2
Support POSIX AIO, post-01635df .  A concrete implementation will be
added by the mio-aio and tokio-file crates
2017-05-21 10:24:08 -06:00
Alex Crichton 01635dfd56 Merge pull request #208 from alexcrichton/poll-ready
Add PollEvented::poll_ready
2017-05-19 14:29:27 -05:00
Alex Crichton 4dd3d30f2a Add PollEvented::poll_ready
This commit adds a general-purpose method for querying the readiness of a
`PollEvented` type. This new method, `poll_ready`, takes a blanket `mio::Ready`
and tests if any part of it is ready. The purpose of this is to expose
platform-specific events through `PollReady` such as `hup` and `error` events
other than just the platform-agnostic readable/writable events.

The semanatics of this method are:

* The `poll_ready` function takes a mask, and the return value is either
  `Async::Ready` with a subset of these events that are ready or `None` if none
  of them are ready.
* There can be up to two tasks blocked on a `PollEvented`, so we need to pick
  which one is suitable for these new events. Currently all events are routed to
  the `read` task unless the writable bit is set. This is mostly only relevant
  for multi-task usage or if you're manually calling `need_read` and/or
  `need_write`, and hopefully the docs will cover this now.
2017-05-19 11:23:00 -07:00
Alex Crichton b92fd2d22a Update to latest mio version 2017-05-19 10:00:57 -07:00
Alex Crichton 9e80c82400 Merge pull request #207 from king6cong/master
typo fix
2017-05-12 09:02:10 -05:00
king6cong 4d8d293913 typo fix 2017-05-12 18:00:55 +08:00
Alex Crichton d723faf2d8 Merge pull request #205 from MarkusJais/master
small typo fixed for io module
2017-05-09 16:13:31 -05:00
Markus Jais 5567ec904e small typo fixed for io module 2017-05-09 21:02:09 +02:00
Alex Crichton 98e99c71c4 Bump to 0.1.7 2017-05-08 16:19:27 -07:00
Alex Crichton 011a7b02f7 Add a test for spawn-in-drop 2017-05-08 16:18:42 -07:00
Alex Crichton 05191f14d7 Merge pull request #204 from fafhrd91/master
drop inner borrow before dropping task
2017-05-08 18:17:32 -05:00
Nikolay Kim 0cfa98566e drop inner borrow before dropping task 2017-05-07 21:17:57 -07:00
Alex Crichton 4545110f45 Merge pull request #201 from munckymagik/update-tokio_rs-links
Update links to pages in the tokio.rs going-deeper section
2017-04-25 14:08:49 -05:00
Dan Munckton 3111443113 Update links to pages in the tokio.rs going-deeper section
See: tokio-rs/website#72
2017-04-25 19:26:43 +01:00
Alex Crichton 29144e6c9b Return NotReady from TcpStream::read_buf 2017-03-27 08:55:30 -07:00
Alex Crichton 8d58b70ce6 Merge pull request #195 from living180/master
Fix logic error in TcpStream.read_buf()
2017-03-27 10:54:18 -05:00
Daniel Harding f5db8136d7 Fix logic error in TcpStream.read_buf()
If the underlying read_bufs() call returned a WouldBlock error,
TcpStream.read_buf() was erroneously calling self.io.need_write(), when
it should actually call self.io.need_read().
2017-03-27 16:54:56 +02:00
Alex Crichton 45e69bfb61 Return NotReady from TcpStream::write_buf
Closes #194
2017-03-27 07:33:18 -07:00
Alex Crichton 37e2870f04 Limit the scope of borrow_mut in consume_queue
Otherwise we may accidentally hold the borrowed ref cell for too long which can
cause a borrow error.

Closes #190
2017-03-15 22:59:08 -07:00
Alex Crichton 8383e8bf7a Remove deprecated benchmark 2017-03-15 22:38:23 -07:00
Alex Crichton c80953f078 Bump to 0.1.6 2017-03-15 10:30:10 -07:00
Alex Crichton 8c1838e093 Fix build on beta/nightly
I believe this happened due to a very recent rustc soundness fix!

Closes #189
2017-03-15 10:29:17 -07:00
Alex Crichton e79f665440 Bump to 0.1.5 2017-03-15 10:06:32 -07:00
Alex Crichton a8e09c5608 Add the proxy example from #100 2017-03-15 09:59:09 -07:00
Alex Crichton 89fcc96dd4 Migrate to using tokio-io
Deprecate the existing `io` module in this crate entirely.

More details coming soon!

Closes #61
2017-03-15 09:46:54 -07:00
Alex Crichton 8fecf98aef Merge pull request #187 from king6cong/master
comment rewording
2017-03-07 09:08:17 -06:00
Alex Crichton b0d04e04f2 Merge pull request #174 from asomers/aioprep
Replace magic numbers with constants from mio
2017-03-07 08:58:37 -06:00
king6cong a67e0d3efb comment rewording 2017-03-07 11:39:51 +08:00
Alan Somers eb66ff3ad1 Replace more instances of magic numbers 2017-03-06 20:16:12 -07:00
Alex Crichton 5c411c548b Add Debug for {Handle,Remote,Core}
Closes #170
2017-03-06 12:16:09 -08:00
Alan Somers 3b8f1695ff Define constants to replace magic numbers 2017-03-05 14:38:55 -07:00
Alex Crichton bd75a522c3 Merge pull request #186 from seeekr/patch-1
fix typo in reactor::Core::run docs
2017-03-03 13:27:41 -06:00
Denis Andrejew 1722d8ed45 fix typo in reactor::Core::run docs 2017-03-03 18:38:56 +00:00
Alex Crichton 6a4df9a3b6 Merge pull request #181 from JanZerebecki/fix-typo-core-run
Fix typo in docblock for Core::run()
2017-02-27 08:46:48 -08:00
Jan Zerebecki e8bd2117d0 Fix typo in docblock for Core::run() 2017-02-27 11:07:19 +01:00
Alex Crichton b773d55444 Tweak Debug output of PollEvented 2017-02-25 21:43:54 -08:00
Alex Crichton 005994cdea Merge pull request #180 from agrover/debug-for-pollevented
Implement Debug for PollEvented<E> if E implements Debug
2017-02-25 23:42:35 -06:00
Andy Grover 9e3f3caad0 Implement Debug for PollEvented<E> if E implements Debug
Useful, esp since mio::unix::EventedFd already implements Debug.

Signed-off-by: Andy Grover <[email protected]>
2017-02-24 12:57:05 -08:00
Alex Crichton 6c774756e6 Merge pull request #173 from partim/easybuf-traits
Add PartialOrd, Ord, and Hash to EasyBuf, generalize PartialEq.
2017-02-21 09:07:24 -06:00
Carl Lerche a3c1796a45 Merge pull request #175 from mayhewj/rename-sender
Rename sender in connect example
2017-02-20 08:26:03 -08:00
Justin Mayhew c9a8208c8a Rename sender in connect example 2017-02-19 15:02:31 -04:00
Martin Hoffmann 54dcd3a015 Add PartialOrd and Ord to EasyBuf, generalize PartialEq. 2017-02-18 20:30:01 +01:00
Alex Crichton 1bc2ef6aff Merge pull request #168 from Byron/master
Implement PartialEq for EasyBuf
2017-02-13 09:36:43 -06:00
Sebastian Thiel fe9a798811 Implement PartialEq for EasyBuf 2017-02-13 07:55:26 +01:00
Alex Crichton a597b962a3 Merge pull request #166 from Byron/master
Allocation in get_mut() always uses 8 * 1024 bytes
2017-02-12 11:27:47 -06:00
Sebastian Thiel 65c5c5241b Test semantics of buffer allocation of get_mut()
* if remaining bytes are smaller then 8 * 1024, allocate 8 * 1024
* otherwise allocate as much as needed to hold the remaining bytes
  without re-allocations.
2017-02-12 09:47:03 +01:00
Sebastian Thiel e11dd06ead Assure we don't have to allocate while growing the vector
We now have enough capacity to copy the unconsumed portion
of the previous frame.
2017-02-11 10:23:02 +01:00
Sebastian Thiel 5adde38a65 Allocation in get_mut() always uses 8 * 1024 bytes
The previous implementation would always use the capacity
of the previous buffer, which would effectively prevent it
from ever shrinking.

This also means that protocol with greater variance in
possible frame sizes would likely be heavily over-allocating.
If these implementations use zero-copy, this would imply
that even small frames kept alive by the client would use
large amounts of memory.

The change is motivated by the implementation of the
cassandra-protocol, which allows frames of up to 256MB
in size, which solely depend on the kind of query.
2017-02-11 09:01:07 +01:00
Alex Crichton 574b6f0c54 Merge pull request #162 from manuel-woelker/master
impl Into<Vec<u8>> for EasyBuf (cf. #120)
2017-02-10 18:32:00 -06:00
Manuel Woelker b4cd223476 impl Into<Vec<u8>> for EasyBuf (cf. #120) 2017-02-10 23:01:46 +01:00
Manuel Woelker f86addf113 fix allocating EasyBuf::get_mut() leaving vector too large (cf. #162) 2017-02-10 22:58:16 +01:00
Alex Crichton a4017ee846 Merge pull request #164 from fortytw2/patch-1
rename sock -> listener in docs
2017-02-08 12:40:33 -08:00
Ian Chiles 8a360f87f5 rename sock -> listener in docs
Makes it much clearer for someone fairly new to rust (like me) to follow along when the same named variable aren't totally different things :)
2017-02-08 20:23:54 +01:00
Alex Crichton cecaad715d Merge pull request #161 from seeekr/patch-1
Fix typo in non-doc comment in copy.rs
2017-01-27 14:49:41 -08:00
Denis Andrejew e31b76c047 Fix typo in non-doc comment in copy.rs 2017-01-27 22:42:04 +00:00
Alex Crichton 05f01d6c9b Merge pull request #157 from seanmonstar/vecio
add read_bufs and write_bufs to Io and TcpStream
2017-01-27 14:34:26 -08:00
Sean McArthur 829563ccfc add read_bufs and write_bufs to Io and TcpStream 2017-01-27 11:32:08 -08:00
Alex Crichton cf74a6b2c9 Merge pull request #159 from jtescher/fix-typos
Fix typos
2017-01-24 21:05:21 -08:00
Julian Tescher baeb35b6d4 Fix typos 2017-01-24 20:52:48 -08:00
Alex Crichton a4b4d57cb7 Touch up TcpStream::from_stream 2017-01-24 16:39:01 -08:00
Alex Crichton 4363663dea Merge pull request #158 from GuillaumeGomez/from_stream
Add from_stream method
2017-01-24 16:37:28 -08:00
Guillaume Gomez c1f1320203 Add from_stream method 2017-01-24 23:49:50 +01:00
Alex Crichton 5b425dfed9 Remove unneeded macro_use 2017-01-23 20:16:12 -08:00
Alex Crichton fcdeb0e5d6 Update crates.io metadata 2017-01-23 20:15:49 -08:00
Alex Crichton 75fe37bc8c Bump to 0.1.4 2017-01-23 20:14:28 -08:00
Alex Crichton c9d0fe59dd Add a fast path to TcpListener::accept 2017-01-23 20:12:01 -08:00
Alex Crichton b22b797278 Add a function to upgrade a Remote to a Handle
Intended for fast paths which can be a little more optimized for when they're
run directly on the event loop.
2017-01-23 20:11:37 -08:00
Alex Crichton e69b67fcfe Remove extraneous clone in Remote 2017-01-23 20:06:03 -08:00
Manuel Woelker b9e182a2ce impl fmt::Debug for EasyBuf (cf. #120)
Debug format looks like this for small resp. long buffers

EasyBuf{len=2/6 [5, 6]}
EasyBuf{len=255/255 [0, 1, 2, 3, ..., 251, 252, 253, 254]}
2017-01-22 21:10:48 +01:00
Alex Crichton e8d4524586 Merge pull request #149 from vorner/loop_id
Provide a publicly-accessible Core ID
2017-01-18 15:33:55 -08:00
Michal 'vorner' Vaner 8d02a1c2b6 Provide a publicly-accessible Core ID
Allow distinguishing between multiple `Core`s and associating data with
them through a `HashMap` or similar.
2017-01-17 22:09:31 +01:00
Alex Crichton 9fe0bc1907 Merge pull request #145 from azdle/udp-codec-tweaks
UDP Codec Example Tweaks
2017-01-15 10:17:57 -08:00
Patrick Barrett 0c553f958a return implicitly (rather than both explicitly and implicitly) 2017-01-14 13:00:46 -06:00
Patrick Barrett e502603532 use the 'Out' type in encode rather than copy/paste 2017-01-14 12:59:22 -06:00
Alex Crichton d0833074d6 Move from a custom channel to futures::sync
Closes #143
2017-01-11 11:35:45 -08:00
Alex Crichton c47c445be6 Add some docs links and such 2017-01-11 09:47:12 -08:00
Alex Crichton 28ace4d33c Update docs/homepage link 2017-01-11 09:21:01 -08:00
Alex Crichton 1985eae7f5 Point to tokio.rs 2017-01-11 09:14:50 -08:00
Alex Crichton f77fe7d3b5 Allow a bit of sloppiness in the timeout test 2017-01-10 16:14:54 -08:00
Alex Crichton 9294b1345c Touch up some docs in tokio-core 2017-01-10 10:02:15 -08:00
Alex Crichton c61d3bc71e Merge pull request #144 from critiqjo/docs-fix
Docs: Remove outdated reference to `task::poll_on`
2017-01-09 21:19:10 -08:00
critiqjo 372d55ce0b Docs: Remove outdated reference to task::poll_on 2017-01-10 10:09:47 +05:30
Alex Crichton 2810471035 Update docs to docs.rs 2017-01-09 16:40:16 -08:00
Alex Crichton 76c3e162b7 Bump to 0.1.3 2017-01-06 11:39:38 -08:00
Alex Crichton 64c360c30e Touch up TcpStream::connect and revert breaking change 2017-01-06 11:37:46 -08:00
Alex Crichton 2499dd35a2 Merge branch 'master' of https://github.com/alreece45/tokio-core 2017-01-06 11:30:18 -08:00
Alex Crichton 4eb036d3f6 Merge pull request #141 from critiqjo/depr-fix
Update the use of deprecated APIs
2017-01-05 09:32:34 -08:00
critiqjo e5bbf004d3 Update the use of deprecated APIs
For stuff that moved from futures::task to futures::executor
2017-01-05 20:41:36 +05:30
Alex Crichton ff7fcd1074 Merge pull request #140 from SirVer/patch-1
Fix typo.
2017-01-04 08:43:00 -08:00
Alex Crichton ae314245dc Merge pull request #139 from sinkuu/use_io_result
Use `io::Result`
2017-01-04 08:42:10 -08:00
Holger Rapp 58913c80a3 Fix typo. 2017-01-04 16:49:33 +01:00
sinkuu 5929a59aca Use io::Result 2017-01-04 17:47:20 +09:00
Alex Crichton 717e99ca80 Fix connect example 2016-12-20 18:39:44 -08:00
Alex Crichton 99078c5cc1 Touch up comments on echo, add connect example 2016-12-20 17:59:46 -08:00
Alexander Reece 3dd4178bb5 Update TcpStream::connect_stream() to return TcpStreamNew 2016-12-20 20:41:13 -05:00
Alexander Reece 000e9b5ab9 Change TcpStream::new() and TcpStream::connect() to return concrete types. 2016-12-20 20:41:13 -05:00
Alex Crichton 50f007a49b Add #![doc] to crate root 2016-12-19 22:41:41 -08:00
Alex Crichton 7b7b3a817b Merge pull request #131 from sfackler/patch-1
`Encode`/`Decode` -> `Codec` in docs
2016-12-19 22:28:49 -08:00
Steven Fackler 24d941d676 Encode/Decode -> Codec in docs 2016-12-19 22:19:39 -08:00
Alex Crichton b9f7808f6e Bump to 0.1.2 2016-12-19 00:37:27 -08:00
Alex Crichton 0588204048 Merge pull request #128 from aturon/from_vec
Add From<Vec<u8>> and Clone impls to EasyBuf
2016-12-17 14:27:40 -08:00
Aaron Turon 46d68f739a Add Clone for EasyBuf 2016-12-17 14:17:52 -08:00
Aaron Turon 9bb1366f33 Add From<Vec<u8>> for EasyBuf 2016-12-17 14:16:47 -08:00
Alex Crichton ef89def808 Touch up docs of TcpListener::accept 2016-12-16 11:15:34 -08:00
Alex Crichton edf6a57450 Minor tweaks w/ TcpListener::accept 2016-12-16 11:13:08 -08:00
Alex Crichton 68a8f26b40 Merge pull request #106 from dpc/tcplistener-accept
Implement `TcpListener::accept()`
2016-12-16 11:10:20 -08:00
Alex Crichton e0990e8a5a Merge pull request #126 from dwrensha/slab-capacity-one
initialize slabs with capacity of one
2016-12-16 11:07:17 -08:00
Dawid Ciężarkiewicz 1864ecc46f tcp: Express incoming in terms of accept 2016-12-16 11:07:08 -08:00
David Renshaw 7abe6db0ae initialize slabs with capacity of one 2016-12-16 13:37:59 -05:00
Dawid Ciężarkiewicz 936727fa52 Don't block in TcpListener::accept
Instead hold a pending Future of the next `TcpStream`.
2016-12-16 10:35:42 -08:00
Dawid Ciężarkiewicz 38df0d7f0f Implement TcpListener::accept() 2016-12-16 10:35:42 -08:00
Alex Crichton f036691681 Clean up the pipe-hup test slightly 2016-12-08 16:30:18 -08:00
Andreas Rottmann 5bab8e85b9 Handle hup events as indicating read readiness
Using Linux's `epoll(7)` interface, a `EPOLLHUP` condition is
signalled for the reading end of a pipe or socket when the other end
is closed for writing. This may happen in combination with `EPOLLIN`
being signalled (if further data is available for reading), or with
`EPOLLIN`.

If `EPOLLHUP` is signalled without `EPOLLIN` it indicates an immediate
EOF condition, which will result in the next `read()` suceeding with 0
bytes read. It is thus not required to handle `EPOLLHUP` specially in
the reader, but we need to indicate readiness upon encountering it.

Looking at the `kqueue` and `windows` mio backends, they seem to be
turn a detected EOF and connection reset into `mio::Ready::hup()`
events, so it may be reasonable to speculate that this change is an
improvement for these platforms as well.

Fixes #117.
2016-12-08 17:52:40 +01:00
Andreas Rottmann dc27c0a524 Add test for EPOLLHUP without EPOLLIN
Note that this brings in a lot of machinery just for the sake of
wrapping file descriptors as PollEvented. This should maybe be moved
into the public API of some crate.
2016-12-08 17:52:40 +01:00
Alex Crichton 3b38e518ca Bump to 0.1.1 2016-11-22 15:39:13 -08:00
Alex Crichton 7f96b7e9e4 Add some more public exports 2016-11-22 15:36:19 -08:00
Alex Crichton b89150c464 Fixup Result-returning encode method 2016-11-22 15:22:30 -08:00
Alex Crichton e970e9a79c Merge branch 'master' of https://github.com/colindjk/tokio-core 2016-11-22 13:07:01 -08:00
Alex Crichton 1a48b79474 Touch up examples to ensure consistency 2016-11-22 12:35:30 -08:00
Alex Crichton 9b62ade962 Touch up codes for UDP
* Move to `std::net` as it's all purely UDP related
* Rename to `UdpCodec` and `UdpFramed` to give a consistent `Udp` prefix
* Add `RecvDgram`, rename `SendDGram` to `SendDgram`
* Touch up some style here and there
2016-11-22 11:48:09 -08:00
Alex Crichton 0d10b0e05a Merge branch 'udp_frame' of https://github.com/rrichardson/tokio-core 2016-11-22 09:44:29 -08:00
Alex Crichton 56c2c31bcf Depend on futures from crates.io 2016-11-22 09:40:35 -08:00
Rick Richardson 1a6753df1f added Default Codec for Udp 2016-11-22 08:47:57 -08:00
Rick Richardson 2cb600bd19 changed CodecUdp::decode to return Self::In instead of Option<Self::In> 2016-11-22 08:29:02 -08:00
Alex Crichton b2ac1d8f93 Merge pull request #111 from tailhook/no_split
Remove `Framed::split` because it's now in futures crate
2016-11-21 14:21:25 -06:00
Rick Richardson b12d32ce1c made send_dgram move self, made FramedUdp::new private, other clean-ups and tweaks 2016-11-21 11:28:25 -08:00
Paul Colomiets e27abd3841 Remove Framed::split because it's now in futures 2016-11-21 19:33:07 +02:00
kibbles dcf994d517 Updated 'encode' return value to Result, removed parameter passing buffer 2016-11-20 21:44:23 -05:00
Rick Richardson ab3915d47d forgot a = 2016-11-20 11:55:57 -08:00
Rick Richardson 161811de8b moved udp test to examples, optimized buffer handling 2016-11-20 11:40:43 -08:00
Rick Richardson 71d8672aab implemented moste of udp frames test 2016-11-20 09:08:03 -08:00
Alex Crichton 4994f762a9 Fix benchmark on nightly 2016-11-19 10:02:12 -08:00
Alex Crichton 1305f105cb Update travis token 2016-11-19 09:40:33 -08:00
Rick Richardson 592a99bca4 completed basic implementation of FramedUdp for streams and sink 2016-11-19 09:05:00 -08:00
Alex Crichton 0f49a69a06 Deprecate the channel module
The `futures::sync::mpsc` module should entirely supplant it.
2016-11-18 15:20:39 -08:00
Alex Crichton bd86bab42d Merge pull request #107 from norcalli/patch-1
Grammar in README.md
2016-11-18 09:05:09 -06:00
Ashkan Kiani bc16ad039d Grammar in README.md 2016-11-17 22:20:36 -08:00
Alex Crichton 1bc3899016 Merge pull request #104 from danburkert/master
Clean up Sink implementation on Framed
2016-11-16 22:41:24 -06:00
Dan Burkert 46dd38b7d7 Clean up Sink implementation on Framed
This commit makes a few changes to the Sink implementation on Framed:

* Backpressure is implemented for `start_send`. If the write buffer is
  over 8KiB and can't be flushed, no new items are accepted.
* 0 length writes to the upstream transport are translated into a
  `WriteZero` error, as with `io::Write::write_all`. `write_all` checks
  for and ignores `Interrupted` errors, but I do not think this is
  necessary for non-blocking writes.
* In `poll_complete`, the upstream transport is not flushed until
  *after* writing the entire write buffer.
2016-11-16 18:42:30 -08:00
Alex Crichton 89a9ab6d34 Merge pull request #102 from aturon/decoder-encoder
Reintroduce "decoder" and "encoder" for Decode and Encode, merging them into Codec
2016-11-15 10:42:34 -06:00
Aaron Turon c353de13fc Reintroduce "decoder" and "encoder" for Decode and Encode, and merge the
traits into `Codec`

A previous commit refactored such that `Encode` and `Decode` are
implemented directly on the types being encoded or decoded. This was
thought to be less expressive but more convenient than having a separate
notion of a (stateful) encoder or decoder.

However, there are certain situations where the approach is just too
limiting: you're required to implemented `Decode` and `Encode` for types
you don't "own" and can't newtype.

This commit moves back to a setup where `Self` represents the
encoder/decoder state; it also merges the two traits into a single
`Codec` trait, since they are currently always used together.
2016-11-15 08:28:26 -08:00
Alex Crichton 21851dd25c Merge pull request #103 from bheesham/failing-tests
Remove references to EasyFramed and easy module.
2016-11-15 00:07:54 -06:00
Bheesham Persaud 06a4c5e2d5 Remove references to EasyFramed and easy module. 2016-11-15 00:42:46 -05:00
Alex Crichton f6241b6330 Touch up Reactor::poll 2016-11-11 14:27:49 -08:00
Alex Crichton 092574b7de Merge branch 'aphs-core-stream' of https://github.com/aidanhs/tokio-core 2016-11-11 14:06:03 -08:00
Alex Crichton 6e7410567c Typo 2016-11-11 11:26:07 -08:00
Alex Crichton 3d69a8b7d0 Add a benchmark for futures channel latency 2016-11-10 20:10:02 -08:00
Alex Crichton bbea632e04 Touch up some of the benchmarks 2016-11-10 19:50:44 -08:00
Alex Crichton 6b888ea20f Merge branch 'benches' of https://github.com/dpc/tokio-core 2016-11-10 19:33:27 -08:00
Dawid Ciężarkiewicz 7ae124077e Improve latency benchmarks. 2016-11-10 14:21:37 -08:00
Aaron Turon 17faf329e0 Add note about how to get a Framed 2016-11-10 09:46:23 -08:00
Aaron Turon 91347f44a5 Remove mentions of EasyFramed 2016-11-10 09:45:09 -08:00
Alex Crichton da3544f468 Merge pull request #97 from k4rtik/patch-1
Correct client invocation example
2016-11-09 10:11:02 -07:00
Kartik Singhal be7992e639 This works only for IPv4 addresses 2016-11-09 12:10:07 -05:00
Kartik Singhal 71baa4967d Correct client invocation example 2016-11-09 11:41:37 -05:00
Dawid Ciężarkiewicz 307ba7a867 travis: Run cargo bench on nightly 2016-11-08 19:09:26 -08:00
Dawid Ciężarkiewicz d1a2a9d324 Add channel_lantency and fix previous issues.
Warmup round before actually performing the test seems to eliminate
variance.
2016-11-08 19:01:37 -08:00
Alex Crichton 45fc13071c Fix line-frames test 2016-11-08 17:59:37 -08:00
Alex Crichton c459b9835c Merge pull request #95 from aturon/sink
Refactor framing to use Streams and Sinks
2016-11-08 16:53:21 -07:00
Aaron Turon 36e3dbf418 Refactor framing to use Streams and Sinks
- Gets rid of `easy` module, instead providing framing support directly
  in the `io` module.

- In particular, adds a framing adapter directly to the `Io` trait,
  which gives you a Stream + Sink object. That object can then be
  `split` into separate `Stream` and `Sink` objects if needed.

- Deprecates the `FramedIo` trait; that's now just Stream + Sink.

- Updates the line framing test to use the stream/sink combinators.
2016-11-08 15:47:13 -08:00
Alex Crichton 3eac142e5f Merge pull request #93 from danburkert/master
Depend directly on git version of futures-rs
2016-11-08 09:32:32 -07:00
Dan Burkert 9dce803e4a Depend directly on git version of futures-rs
Cargo replace directives are not meant for libraries, since they are not
transitively inherited by the application.
2016-11-07 20:22:06 -08:00
Aaron Turon 60796f40fd Merge pull request #82 from aturon/cleanup-for-0.1
Polish tokio-core in prep for overall 0.1 release
2016-11-06 15:26:01 -08:00
Aidan Hobson Sayers fce913c04d Add turn on Core to allow single event loop iterations 2016-11-06 22:11:18 +00:00
Alex Crichton 4744a2e48b No more need for lazy in chat example 2016-11-05 13:36:49 -07:00
Alex Crichton 6dc8333fb2 Merge pull request #92 from dwrensha/typo
Fix some typos.
2016-11-05 13:33:01 -07:00
David Renshaw f96d37ccf3 Fix some typos. 2016-11-05 16:29:54 -04:00
Alex Crichton 79136ca211 Merge pull request #91 from dwrensha/simplify-echo
Simply echo example: split() can now happen on the main task.
2016-11-05 12:49:37 -07:00
David Renshaw 556143b7c6 Simply echo example: split() can now happen on the main task. 2016-11-05 15:16:29 -04:00
Alex Crichton 614887b8c1 Implement split() with BiLock 2016-11-05 11:14:54 -07:00
Dawid Ciężarkiewicz 8e7ed8ae21 Add some benchmarks.
To be moved into separate repo.
2016-11-04 22:06:08 -07:00
Alex Crichton 0a3dc0bb75 Add a method to manually deregister an I/O object
Typically this happens automatically as the `E` in `PollEvented<E>` is an owned
reference (e.g. a `TcpStream`) where dropping that will close the resource,
automatically unregistering it from the event loop. In some situations, however,
this isn't always the case, so the deregistering needs to happen manually.
2016-11-04 09:12:00 -07:00
Alex Crichton 4615c3ea78 Touch up the echo examples 2016-11-02 16:57:27 -07:00
Dawid Ciężarkiewicz 237bcead7a Add UDP echo server example. 2016-11-02 16:30:37 -07:00
Aaron Turon 503f4a0405 Polish tokio-core in prep for overall 0.1 release
This commit makes a few tweaks to the new `easy` module:

- Rename `Parse` to `Decode`, and `Serialize` to `Encode`.

- Don't use `Poll` for the `decode` method; we prefer to reserve
  that type for actual aync events, and in particular for a `NotReady`
  result to imply that some task scheduling has taken place. Instead,
  use an internal `Option`.
2016-10-25 15:15:18 -07:00
Alex Crichton 623ce443d8 Add some warning comments 2016-10-24 20:03:27 -07:00
Alex Crichton 88fb0b32af Merge pull request #76 from spinda/into_inner
Add methods to extract inner from EasyFramed
2016-10-24 20:02:31 -07:00
Alex Crichton bb22ef5f82 Merge pull request #78 from Archytaus/master
Fix typo in TcpStream and UdpSocket documentation
2016-10-24 19:22:59 -07:00
Ryan Scott c9554fa174 Fixed a small typo of 'writey' where it was expected to be 'ready' in TcpStream and UdpSocket documentation. 2016-10-25 10:13:52 +09:00
Michael Smith a1dfa14034 Add methods to extract inner from EasyFramed 2016-10-24 09:17:40 -07:00
Alex Crichton 37a2bed4cf Merge pull request #72 from dwrensha/copy-edit
Fix typo and awkward sentences.
2016-10-22 21:20:29 -07:00
David Renshaw 4a07828095 Fix typo and awkward sentences. 2016-10-23 11:14:52 +08:00
Alex Crichton cefdb0c321 Merge pull request #71 from plietar/master
Allow start and end of window to match length of underlying slice.
2016-10-22 16:21:49 -07:00
Paul Lietar 4719fbdb28 Allow start and end of window to match length of underlying slice. 2016-10-22 15:56:02 +02:00
Alex Crichton 6d6c2aa390 Fix tests 2016-10-21 17:01:43 -07:00
Alex Crichton 2c5e4ebba8 Merge pull request #64 from alexcrichton/add-bytes
Move Framed from tokio-proto to core
2016-10-21 16:10:08 -07:00
Alex Crichton b84ef90a98 Move Framed from tokio-proto to core
This commit extracts the concrete implementation of `FrameIo` in tokio-proto to
tokio-core under the name `EasyFramed`. This extraction is accompanied with a
new `EasyBuf` buffer type to work with when parsing types.

The purpose of this movement is to provide a clear and easy entry point at the
`FramedIo` layer for those who need it. Eventually these buffer types will get
replaced or moved to the `bytes` crate, but in the interest of an 0.1 release
and remaining backwards compatible with the tokio-core 0.1 release this is
adding a separate module.
2016-10-21 11:46:32 -07:00
Alex Crichton 3ced812993 Merge pull request #55 from oconnor663/read_once
rename Read to ReadOnce and expose it
2016-10-16 13:32:45 -07:00
Jack O'Connor 6789527952 rename ReadOnce back to Read, but keep it exposed 2016-10-15 09:46:59 -04:00
Alex Crichton eecf3d129c Merge pull request #58 from oberien/master
fix(examples): Fix typos in chat example
2016-10-14 14:48:46 -07:00
oberien 7cf7833631 fix(examples): Fix typos in chat example
Rephrase a sentence to not contain the word `join` when we are actually using
`select` to prevent confusion.
2016-10-14 23:03:46 +02:00
Alex Crichton bc2f857236 Touch up the chat example 2016-10-13 11:36:32 -07:00
Alex Crichton 688b67c8d8 Don't need regex from env_logger 2016-10-12 23:34:58 -07:00
Alex Crichton 227f454c52 Merge branch 'master' of https://github.com/oberien/tokio-core 2016-10-12 23:33:29 -07:00
oberien 315f601822 ref(examples): Minor refactoring in chat example
* Move connections-clone down a bit
* Use `Ok` and `Err` as IntoFuture
2016-10-11 20:08:13 +02:00
Alex Crichton 62514fc40b Merge pull request #52 from tailhook/intervals
Implement `tokio_core::reactor::Interval`
2016-10-10 08:00:22 -07:00
Paul Colomiets b1d02eb598 Implement tokio_core::reactor::Interval 2016-10-10 15:41:57 +03:00
Jack O'Connor da37ad0948 rename Read to ReadOnce and expose it
The other read futures (read_exact, read_until, etc.) all expose their
concrete future types so that function signatures can return them, but
until now `read()` didn't. Exposing it with the name "Read" causes
naming conflicts with the std::io::Read trait, so the easiest thing to
do is to just change the name. Importing std::io::Read under a different
name would've been an option too, but that would probably be annoying
for consumers in the same way it's annoying for us.

The original PR (https://github.com/tokio-rs/tokio-core/pull/29) decided
that "read" was a better name than "read_some", so I'm leaving the top
level functions unchanged. I don't have a strong opinion about it one
way or the other, but I *do* think it's worth bikeshedding a little bit.
Python's asyncio library actually ended up with a very similar issue
around naming inconsistency between the sync and async worlds, and we
can hopefully avoid repeating that: https://bugs.python.org/issue22279
2016-10-08 01:28:39 -04:00
oberien b227738bd7 ref(chat): Make code more readable
* Send source address of message in addition to the message to connected clients.
* Move `spawn_fn` to the bottom.
* Use `map` instead of `and_then` if there is no need for blocking.
* `map` to unit where values are not needed anymore.
2016-10-07 14:57:30 +02:00
Paul Colomiets 411caa786d Moves when to Timeout from TimeoutToken 2016-10-06 21:11:46 +03:00
oberien 6961efa8dd fix(chat): Implement alexcrichton's suggestions
* Remove unnecessary clone
* Improve rightward drift
* Remove unnecessary lazy future
* Improve utf-8 handling
* Refactor to make code more understandable
2016-10-06 15:38:20 +02:00
Alex Crichton a99b2529e0 Merge pull request #51 from debris/patch-1
fixed typo in split.rs
2016-10-05 09:03:02 -07:00
Marek Kotewicz a94be1bca9 fixed typo in split.rs 2016-10-05 11:28:46 +02:00
oberien 0205b855d0 Add Chat example 2016-10-04 20:02:52 +02:00
Alex Crichton e32115b1b4 Merge pull request #50 from oberien/read
doc(read): Add number of bytes read to doc
2016-10-04 07:50:44 -07:00
Alex Crichton 37879bd911 Merge pull request #49 from oberien/read_until
doc(read_until): Fix typo in doc
2016-10-04 07:46:36 -07:00
oberien b0033eb463 doc(read): Add number of bytes read to doc 2016-10-04 13:56:31 +02:00
oberien 2545237309 doc(read_until): Fix typo in doc 2016-10-04 13:34:25 +02:00
Alex Crichton f019f5f5bb Merge pull request #48 from oberien/read_until
feat(io): Add `read_until`
2016-10-03 09:34:11 -07:00
oberien d2440a4059 fix(read_until): Make read_until resemble BufRead::read_until 2016-09-30 22:12:56 +02:00
oberien ce8a9d460e feat(io): Add read_until 2016-09-30 22:06:43 +02:00
Alex Crichton 866dad2e85 Merge pull request #29 from 3Hren/master
Add `read` free function to read some bytes
2016-09-30 10:14:10 -07:00
Evgeny Safronov f69f748470 chore: fix panic string 2016-09-30 13:20:22 +03:00
Evgeny Safronov 42bbe86cb6 refactor: rename ReadSome to Read
Also `try_nb!` is used.
2016-09-30 13:14:41 +03:00
Evgeny Safronov 4b3472ceae refactor: rename, also make EOF as a valid result 2016-09-29 12:19:20 +03:00
Alex Crichton e92d4bf52b Merge pull request #47 from oberien/spawn_fn
doc(spawn_fn): Fix typo
2016-09-28 10:22:47 +09:00
oberien f62d1ddc8d doc(spawn_fn): Fix typo 2016-09-28 03:20:33 +02:00
Alex Crichton 1d40bf14f7 Add Handle::spawn_fn
Acts as a convenience to avoid `futures::lazy`.

Closes #40
2016-09-26 16:52:54 -07:00
Alex Crichton c2e80ebb30 Indiciate need_read requires poll_read
Original intention was that it didn't, but nowadays it does.

Closes #44
2016-09-26 16:27:29 -07:00
Alex Crichton 181dcdd9ea Merge pull request #39 from NeoLegends/patch-1
Fix documentation typos
2016-09-26 05:04:02 +09:00
Moritz Gunz 326537b861 Fix documentation typos 2016-09-21 18:27:25 +02:00
xenor f41c55f9f7 Instead of calling handle() a second time in line 26, I used a reference to the value obtained in line 23. 2016-09-20 09:59:09 -07:00
Alex Crichton 418a973520 Add poll_{read,write} on halves
Closes #32
2016-09-14 11:14:18 -07:00
Evgeny Safronov fb497aba44 Add read_some free function to read some bytes 2016-09-12 19:52:44 +03:00
Alex Crichton 933b34cd25 Merge pull request #27 from sbstp/net-docs
update the docs of net::*::bind
2016-09-11 10:55:55 -07:00
Simon Bernier St-Pierre 32ccf255b5 update the docs of net::*::bind 2016-09-10 19:12:30 -04:00
Alex Crichton 00fb7ea4a3 Update readme with crates.io dep 2016-09-09 18:15:15 -07:00
Alex Crichton 550dc76bbd Depend on futures from crates.io 2016-09-09 18:02:03 -07:00
Alex Crichton 80d23caa5e Merge pull request #25 from sdroege/remove-udpsocket-new
Remove now unused UdpSocketNew
2016-09-09 09:48:06 -07:00
Alex Crichton b2ae5ac7c9 Remove unused UdpSocketNew 2016-09-09 09:47:35 -07:00
Sebastian Dröge ab5025a8b7 Remove now unused UdpSocketNew
See https://github.com/tokio-rs/tokio-core/issues/15#issuecomment-245552463
2016-09-09 19:23:42 +03:00
Alex Crichton 8f92dc9d56 Add a simple "hello" example 2016-09-09 00:11:08 -07:00
Carl Lerche 0000210e0c Add io::FramedIo 2016-09-08 23:25:17 -07:00
Alex Crichton 83784fd983 Don't remove timeouts that have fired
Closes #22
2016-09-08 07:47:07 -07:00
Alex Crichton cd331dde34 Merge pull request #23 from frewsxcv/docs
Add links in docs to `channel` function.
2016-09-08 07:35:49 -07:00
Corey Farwell eb643c4d9e Add links in docs to channel function. 2016-09-08 10:33:41 -04:00
Alex Crichton 1f0d2198ad Use a timer heap instead of a timer wheel
In general it's easier to implement and should have more predictable performance
semantics for applications in general. More serious timer usage can go through
`tokio-timer` which has properly configurable timer wheels and such.

Closes #2
Closes #7
2016-09-08 00:06:34 -07:00
Alex Crichton 66cff8e84b Swap Handle/Pinned
* Handle -> Remote
* Pinned -> Handle

All APIs now take a `&Handle` by default and in general can return an immediate
`io::Result` instead of an `IoFuture`. This reflects how most usage will likely
be done through handles rather than remotes, and also all previous functionality
can be recovered with a `oneshot` plus `Remote::spawn`.

Closes #15
2016-09-07 22:12:41 -07:00
Alex Crichton e60002b653 Tweak TaskIo wording and such
* Remove TaskIo
* task_split -> split
* TaskIoRead -> ReadHalf
* TaskIoWrite -> WriteHalf

Closes #18
2016-09-07 22:12:14 -07:00
Alex Crichton 6c045d31ac Reorganize the entire crate:
Renamed APIs

* Loop => reactor::Core
* LoopHandle => reactor::Handle
* LoopPin => reactor::Pinned
* TcpStream => net::TcpStream
* TcpListener => net::TcpListener
* UdpSocket => net::UdpSocket
* Sender => channel::Sender
* Receiver => channel::Receiver
* Timeout => reactor::Timeout
* ReadinessStream => reactor::PollEvented
* All `LoopHandle` methods to construct objects are now free functions on the
  associated types, e.g. `LoopHandle::tcp_listen` is now `TcpListener::bind`
* All APIs taking a `Handle` now take a `Handle` as the last argument
* All future-returning APIs now return concrete types instead of trait objects

Added APIs

* io::Io trait -- Read + Write + ability to poll

Removed without replacement:

* AddSource
* AddTimeout
* IoToken
* TimeoutToken

Closes #3
Closes #6
2016-09-07 22:12:14 -07:00
Alex Crichton 93c61bb384 Merge pull request #21 from frewsxcv/clippy
Address a few clippy suggestions.
2016-09-07 21:19:40 -07:00
Alex Crichton 0eeeca4ac1 Merge pull request #20 from frewsxcv/docs
Add documentation links.
2016-09-07 21:19:12 -07:00
Corey Farwell 9fe1d8aeca Remove unnecessary return statements. 2016-09-07 21:30:11 -04:00
Corey Farwell a9d24810be Avoid unnecessary Option::expect indirection. 2016-09-07 21:29:52 -04:00
Corey Farwell 93e1d4778d Use while..let construct for loop. 2016-09-07 21:29:37 -04:00
Corey Farwell d7f76ca549 Add documentation links. 2016-09-07 21:19:34 -04:00
Alex Crichton 815dc803db Merge pull request #19 from kamalmarhubi/read-exact-doc
docs: Fix copypasta in read_exact docs
2016-09-07 15:25:40 -07:00
Kamal Marhubi abf4521300 docs: Fix copypasta in read_exact docs 2016-09-07 18:12:09 -04:00
Alex Crichton 03ac1ea460 Merge pull request #14 from reem/patch-1
Fix the link for the echo server example in the README
2016-09-03 10:27:55 -07:00
Jonathan Reem 242f8fa1b2 Fix the link for the echo server example. 2016-09-02 23:22:27 -07:00
Alex Crichton 3794cf7f1d Update with Poll/Async changes 2016-09-02 12:17:38 -07:00
Alex Crichton 3282b3ec0d Update to mio 0.6 2016-09-01 22:14:26 -07:00
Carl Lerche 2081bcc430 Track Slab changes 2016-09-01 10:12:15 -07:00
Alex Crichton 6947933b6b Be sure to call poll before doing I/O
Ensures that we can properly clear the readiness bits and manage them correctly.

Closes #10
2016-09-01 09:27:42 -07:00
Alex Crichton 02538d035f Move binaries to examples 2016-09-01 09:18:03 -07:00
Alex Crichton 6c6fb917ee Merge pull request #8 from nbigaouette/patch-1
Fix typo in Loop::run() documentation
2016-09-01 09:00:14 -07:00
Nicolas Bigaouette 376974c349 Fix typo in Loop::run() documentation
Simple typo fixed (`becuase` -> `because`)
2016-08-31 22:35:19 -04:00
Alex Crichton 330ab823b0 Update to futures master
* Remove `LoopData` as it's no longer necessary
* Add `LoopHandle::spawn` to spawn new futures onto an event loop
* Add `LoopData::spawn` to also spawn new futures onto an event loop
* Rejigger the implementation of the event loop a bit (make a slab of futures),
  but otherwise everything else is pretty constant.
2016-08-31 19:00:42 -07:00
Carl Lerche 440a813c5a Track mio master 2016-08-30 14:45:29 -07:00
Alex Crichton 7a852a7f49 Merge pull request #4 from sinkuu/fix_dropbox
Fix DropBox's drop
2016-08-28 10:56:11 -07:00
sinkuu 909f3e923c Fix DropBox's drop 2016-08-28 16:06:45 +09:00
Alex Crichton c820d67d66 Update to mio master 2016-08-27 12:33:31 -07:00
Alex Crichton b9395808be Merge pull request #1 from sbstp/typo
Fix typo in panic message
2016-08-26 19:11:51 -07:00
Simon Bernier St-Pierre 32557cd832 fix typo in panic message 2016-08-26 21:47:50 -04:00
Alex Crichton 3715e62471 Update appveyor link 2016-08-26 14:57:55 -07:00
Alex Crichton 235812a4da Add license files 2016-08-26 14:56:21 -07:00
Alex Crichton 37a53a1085 Update appveyor status 2016-08-26 14:51:40 -07:00
Alex Crichton 347669ed2b Add appveyor config 2016-08-26 14:45:55 -07:00
Alex Crichton d6e8998582 Update travis token 2016-08-26 14:44:01 -07:00
Alex Crichton f107c8d860 Rename to tokio-core, add in futures-io
Renames the futures-mio crate to tokio-core, pulls in the futures-io crate under
an `io` module, and gets everything compiling.
2016-08-26 14:39:47 -07:00
Alex Crichton e71d509fee Add a &LoopPin to add_loop_data closures
This way they can use that proof that they're running on the event loop
2016-08-24 18:44:47 -07:00
Alex Crichton d1cd455225 Implement Stream for Receiver
That's... what it is!
2016-08-22 10:10:03 -07:00
Aaron Turon cff73b7a9d Merge pull request #87 from alexcrichton/less-arc
Don't store an Arc in ReadinessStream
2016-08-21 21:18:53 -07:00
Jean Pierre Dudey 9c309af597 Update futures-mio tests 2016-08-21 11:30:59 -04:00
Alex Crichton df9730fcbe Add a channel to the futures-mio crate 2016-08-20 23:41:19 -07:00
Alex Crichton 2bd616df51 Reorganize the event_loop module
Split it up into a number of targeted modules for each purpose, for example loop
data, I/O sources, timeouts, and channels. No actual change is intended to be
part of this commit.
2016-08-20 23:24:56 -07:00
Alex Crichton b9dae23e3f Don't store an Arc in ReadinessStream
This commit contains a few refactorings, but the major goal is to remove the
`Arc` that's stored inside of each `ReadinessStream` and `Scheduled` slot in the
event loop. The original purpose of this `Arc` was to share the I/O object among
the concrete handle itself and the event loop. The event loop would then change
how the socket is registered over time and then deregister it when it gets a
"shutdown request".

Nowadays, however, once an I/O object is registered with the event loop it's
never updated. Additionally, we don't actually need to call `deregister` but can
rather just instead close the I/O object itself and let the kernel/event loop
take care of the cleanup. All we need to do on deregistering is free up the slab
entry.

The major result of this commit is that I/O objects no longer need to be `Sync`
(as they're not stored in an `Arc`). Instead they just need to be `Send +
'static` as one might otherwise expect.

Along the way this also refactors a few pieces here and there to make more sense
in this new scheme. The `ReadinessStream` type now has a type parameter
indicating an owned reference to the I/O object it wraps. This can be accessed
via the `get_ref` and `get_mut` methods. Additionally I/O tokens on the event
loop are now a full-fledged `IoToken` type which we can change in the future if
we need to.
2016-08-20 23:07:00 -07:00
David Renshaw 5ab323e5c2 Revert to using futures::lazy(), which is in fact needed. 2016-08-20 16:22:54 -04:00
David Renshaw a9b53d61d2 update comment and simplify echo example 2016-08-20 11:52:16 -04:00
Alex Crichton 0a707ffccb Update docs of futures-mio 2016-08-18 10:29:11 -07:00
Alex Crichton 12a05b9568 Rewrite recursion with a loop in sink.rs 2016-08-18 09:19:50 -07:00
Alex Crichton 32eb457dad Relax the 'static bound on Loop::run
We know that the future will never persist beyond this stack frame, so we can
just leave its ownership on the stack frame itself and receive notifications off
the event loop that we need to poll it.
2016-08-17 23:34:44 -07:00
Alex Crichton 9672f90091 Remove lots of 'static bounds
The core trait and associated types no longer require the `'static` bounds, and
all associated methods have also had the `'static` bounds removed. The only
location for the `'static` bound is `forget`.

While the restriction of `'static` on `forget` is here to stay, we'll soon
enable `Loop::run` to take a non-`'static` future, allowing driving a
non-`'static` future.
2016-08-17 18:48:21 -07:00
Alex Crichton 8025d85019 Update futures-curl
Also involved yet another round of bug fixes to the timer wheel as well as an
unfortunately serious rejiggering of the level-translation into libcurl. Eew.
2016-08-17 18:41:34 -07:00
Alex Crichton 311bfa07a3 Update futures-minihttp 2016-08-17 18:41:34 -07:00
Alex Crichton d0b911189c Re-work I/O
* Auto-register interest whenever we see WouldBlock
* Remove implementations of `Stream<Item=Ready>`, no longer needed
* Add explicit `poll_{read,write}` methods, if needed
* Remove all I/O streams, libstd ones suffice
* Update all I/O futures
2016-08-17 18:41:34 -07:00
Alex Crichton 293d104177 Remove Future::schedule
A more appealing model is actually just automatically inferring what needs to be
scheduled based on what actions are done during poll. For example if during a
poll you check a oneshot channel, then the current task is registered for being
woken up if it's not ready. Similarly this will apply to I/O where if I/O is
attempted but we see EAGAIN then we'll schedule the task to get notified when
it's ready.

This may also have performance benefits in some niche situations because you
don't need to recompute where you are in the state machine both during poll and
during schedule. Instead, it now happens all at once.
2016-08-17 18:41:34 -07:00
Alex Crichton 62f306629d Keep polling in Buffered if there's more futures
We're not NotReady until we hit the final future and it's not done.
2016-08-15 16:22:09 -07:00
Alex Crichton 217af868e1 Implement UDS bindings
Closes #61
2016-08-15 10:31:23 -07:00
Alex Crichton 8327d327c1 Optimize next_timeout slightly
Avoid moves as it apparently adversely affects perf
2016-08-13 23:29:08 -07:00
Alex Crichton 3158a2c73b Add a method to get a handle from a pin
It's store there anyway!
2016-08-13 23:13:26 -07:00
Alex Crichton b508964db6 Remove Send from Future/Stream
This bound existed for two primary reasons, both detail below, and both of which
have now been solved.

One of the primary reasons this existed was due to the presence of `tailcall`.
Each standard combinator will call `tailcall` as appropriate, storing the
resulting trait object. Storing trait objects influences the applicatoin of the
`Send` and `Sync` bounds normally, but a key insight here is that we're not
storing trait objects but rather just pieces of otherwise internal futures.

With this insight the main storage for these futures, `Collapsed`, could simply
implement `Send` so long as the future itself originally implemented `Send`.
This in turn means that `tailcall` must be an `unsafe` method, but it seems well
worth the benefit of relaxing the `Send` bound.

The second primary reason for this bound was so the `Task` itself could be send.
This is critical for ensuring that futures can receive notifications from
multiple threads (e.g. be a future waiting on sources of multiple events).
Another key insight here, however, is that only the *outer* future needs to be
`Send`. We already have a solution, with `LoopData`, to make non-`Send` data
`Send`. By implementing `Future` directly for `LoopData<F: Future>`, this means
that it's trivial to make any future sendable by simply pinning it to an event
loop!

With these two pieces combined, it means that `Send` is no longer needed as a
bound on the `Future` and `Stream` traits. It may practically mean that
`LoopData` is used commonly in some scenarios, but that's quite a small price to
pay for relaxing the requirements of the core trait.

Some other ramifications of this change are:

* The `Future::boxed` and `Stream::boxed` methods now require `Self` to adhere
  to `Send`. This is expected to be the most common case, and in the less common
  case of not-`Send` `Box::new` can be used.
* Two new type aliases, `BoxFuture` and `BoxStream` have been introduced to
  assist in writing APIs that return a trait object which is `Send`. Both of
  these type aliases package in the `Send` bound.
* A new `LoopPin` type, added in the previous commit, can be used to easily
  generate handles that can be used to pin futures to an event loop without
  having a literal reference to the event loop itself.
2016-08-12 15:39:41 -07:00
Alex Crichton 9911f421eb Add LoopPin to easily create LoopData 2016-08-12 13:42:24 -07:00
Alex Crichton ef3efd4175 Remove the Any bound from LoopData
No need for this, all we need is 'static now
2016-08-12 11:15:34 -07:00
Yale Cason III 0aa7ab94ff Listening vs Listenering
Not trying to be pedantic, just noticed this.
2016-08-11 14:46:16 -04:00
Alex Crichton f08e8ec672 Fix compile on windows 2016-08-10 22:33:45 -07:00
Alex Crichton 18c371b158 Remove extraneous allocation on ReadinessStream::new 2016-08-10 13:58:20 -07:00
Alex Crichton 517d5c7434 Add libcurl bindings 2016-08-09 23:51:14 -07:00
Alex Crichton 7c4bac5166 Fix a few more timer wheel bugs 2016-08-09 22:13:50 -07:00
Alex Crichton 681316dfa1 Fix link in mio README 2016-08-08 23:20:05 -07:00
Alex Crichton 00daa2ca23 Add lots of README files 2016-08-08 23:18:49 -07:00
Alex Crichton 68103727f1 Use the dev branch of mio 2016-08-08 13:22:16 -07:00
Alex Crichton bfe91f9f36 Remove the executable bit on a file 2016-08-08 11:44:16 -07:00
Alex Crichton 8d73133907 write-then-drop is now upstream 2016-08-08 11:00:04 -07:00
Alex Crichton 4380e42587 More info and more READMEs 2016-08-05 16:21:56 -07:00
Alex Crichton 164193fe82 Add a method to add data to an event loop directly
Avoids Send entirely
2016-08-05 15:58:14 -07:00
Alex Crichton 8daac0347d Fix up a few edge cases on the timer wheel 2016-08-05 14:02:27 -07:00
Alex Crichton d2bb8e01fd Implement Sync for LoopData
It's already Sync because it's safe to access amongst many threads by the sheer
fact that data is only accessed on one thread. That is, all other concurrent
accessors, if any, will receive `None`.
2016-08-05 14:01:36 -07:00
Alex Crichton 5b18514970 Add some assorted debug messages 2016-08-05 14:01:24 -07:00
Alex Crichton 42a0a10294 Set the CURRENT_LOOP for processing messages
This ensures that timeouts and callbacks are run with the TLS var set
2016-08-05 14:00:59 -07:00
Alex Crichton 304914b707 Start brushing up io/mio docs 2016-08-05 09:53:50 -07:00
Alex Crichton 8eb1f681af Don't export the timer_wheel module
Move tests into that module
2016-08-05 09:44:00 -07:00
Alex Crichton 368a9c70e8 Fix RefCell borrow_mut error on firing timeouts
The scope was a little longer than intended!
2016-08-05 09:38:41 -07:00
Alex Crichton 5d0fdf26a9 Fix compile of minihttp on stable 2016-08-05 09:25:40 -07:00
Alex Crichton e7f4313cf4 Implementing LoopData
This type acts for a handle to storage of non-`Send` data. The handle itself is
sendable across threads and is therefore suitable for storage in a `Future`.
This data uses communication internally and a new method on `Task` to ensure
that when the data needs to be accessed the future will find its way to the
right thread.

More on this type coming soon!
2016-08-04 20:34:54 -07:00
Alex Crichton 04bd33e390 Add AsRawFd where possible 2016-08-04 12:51:49 -07:00
Alex Crichton 5f9185ef4c Fix timer wheel tests 2016-08-03 23:38:32 -07:00
Alex Crichton 5c9daad88b Add a timer wheel 2016-08-03 22:57:07 -07:00
Alex Crichton 1d7098eece Add a simple UDP test 2016-08-02 23:56:01 -07:00
Alex Crichton c458e23940 Add a few more TCP methods 2016-08-02 22:52:01 -07:00
Alex Crichton 260255e674 Add UDP sockets 2016-08-02 22:49:58 -07:00
Alex Crichton 1b07e91834 Actually do what EventLoop::deschedule says 2016-08-02 10:39:06 -07:00
Alex Crichton 79760da66c Remove DropSource from mio
I'm... not sure if it does anything any more as a `ReadinessStream` isn't
clone-able nor is it split. As a result, I don't think we need it.
2016-08-02 10:37:32 -07:00
Alex Crichton 5970203b21 Finish docs on futures-mio
Also remove mio BufReader/BufWriter for now, they should come back shortly
though
2016-08-01 17:41:58 -07:00
Alex Crichton 7ffe72dc73 Add docs to futures-io crate 2016-08-01 17:30:56 -07:00
Alex Crichton b47b9f5398 Remove README descriptions where not present 2016-07-31 13:58:38 -07:00
Alex Crichton 192579d62a Add some descriptions 2016-07-31 13:55:04 -07:00
Alex Crichton bc64194be1 Let's rename everything! 2016-07-30 22:50:58 -07:00
432 changed files with 57902 additions and 3 deletions
+41
View File
@@ -0,0 +1,41 @@
freebsd_instance:
image: freebsd-12-1-release-amd64
# Test FreeBSD in a full VM on cirrus-ci.com. Test the i686 target too, in the
# same VM. The binary will be built in 32-bit mode, but will execute on a
# 64-bit kernel and in a 64-bit environment. Our tests don't execute any of
# the system's binaries, so the environment shouldn't matter.
task:
name: FreeBSD 12.0
env:
LOOM_MAX_DURATION: 10
setup_script:
- pkg install -y curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh -y
- . $HOME/.cargo/env
- rustup target add i686-unknown-freebsd
- |
# Remove any existing patch statements
mv Cargo.toml Cargo.toml.bck
sed -n '/\[patch.crates-io\]/q;p' Cargo.toml.bck > Cargo.toml
# Patch all crates
cat ci/patch.toml >> Cargo.toml
# Print `Cargo.toml` for debugging
echo "~~~~ Cargo.toml ~~~~"
cat Cargo.toml
echo "~~~~~~~~~~~~~~~~~~~~"
cargo_cache:
folder: $HOME/.cargo/registry
test_script:
- . $HOME/.cargo/env
- cargo test --all
- cargo doc --all
i686_test_script:
- . $HOME/.cargo/env
- |
cargo test --all --exclude tokio-tls --exclude tokio-macros --target i686-unknown-freebsd
before_cache_script:
- rm -rf $HOME/.cargo/registry/index
+51
View File
@@ -0,0 +1,51 @@
<!--
Thank you for reporting an issue.
Please fill in as much of the template below as you're able.
-->
## Version
<!--
List the versions of all `tokio` crates you are using. The easiest way to get
this information is using `cargo-tree`.
`cargo install cargo-tree`
(see install here: https://github.com/sfackler/cargo-tree)
Then:
`cargo tree | grep tokio`
-->
## Platform
<!---
Output of `uname -a` (UNIX), or version and 32 or 64-bit (Windows)
-->
## Subcrates
<!--
If known, please specify the affected Tokio sub crates. Otherwise, delete this
section.
-->
## Description
<!--
Enter your issue details below this comment.
One way to structure the description:
<short summary of the bug>
I tried this code:
<code sample that causes the bug>
I expected to see this happen: <explanation>
Instead, this happened: <explanation>
-->
+23
View File
@@ -0,0 +1,23 @@
<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.
Bug fixes and new features should include tests.
Contributors guide: https://github.com/tokio-rs/tokio/blob/master/CONTRIBUTING.md
-->
## Motivation
<!--
Explain the context and why you're making that change. What is the problem
you're trying to solve? In some cases there is not a problem and this can be
thought of as being the motivation for your change.
-->
## Solution
<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->
+2
View File
@@ -0,0 +1,2 @@
target
Cargo.lock
+387
View File
@@ -0,0 +1,387 @@
# Contributing to Tokio
:balloon: Thanks for your help improving the project! We are so happy to have
you!
There are opportunities to contribute to Tokio at any level. It doesn't matter if
you are just getting started with Rust or are the most weathered expert, we can
use your help.
**No contribution is too small and all contributions are valued.**
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
us!
[dev]: https://gitter.im/tokio-rs/dev
## Conduct
The Tokio project adheres to the [Rust Code of Conduct][coc]. This describes
the _minimum_ behavior expected from all contributors.
[coc]: https://github.com/rust-lang/rust/blob/master/CODE_OF_CONDUCT.md
## Contributing in Issues
For any issue, there are fundamentally three ways an individual can contribute:
1. By opening the issue for discussion: For instance, if you believe that you
have uncovered a bug in Tokio, creating a new issue in the tokio-rs/tokio
issue tracker is the way to report it.
2. By helping to triage the issue: This can be done by providing
supporting details (a test case that demonstrates a bug), providing
suggestions on how to address the issue, or ensuring that the issue is tagged
correctly.
3. By helping to resolve the issue: Typically this is done either in the form of
demonstrating that the issue reported is not a problem after all, or more
often, by opening a Pull Request that changes some bit of something in
Tokio in a concrete and reviewable manner.
**Anybody can participate in any stage of contribution**. We urge you to
participate in the discussion around bugs and participate in reviewing PRs.
### Asking for General Help
If you have reviewed existing documentation and still have questions or are
having problems, you can open an issue asking for help.
In exchange for receiving help, we ask that you contribute back a documentation
PR that helps others avoid the problems that you encountered.
### Submitting a Bug Report
When opening a new issue in the Tokio issue tracker, users will be presented
with a [basic template][template] that should be filled in. If you believe that you have
uncovered a bug, please fill out this form, following the template to the best
of your ability. Do not worry if you cannot answer every detail, just fill in
what you can.
The two most important pieces of information we need in order to properly
evaluate the report is a description of the behavior you are seeing and a simple
test case we can use to recreate the problem on our own. If we cannot recreate
the issue, it becomes impossible for us to fix.
In order to rule out the possibility of bugs introduced by userland code, test
cases should be limited, as much as possible, to using only Tokio APIs.
See [How to create a Minimal, Complete, and Verifiable example][mcve].
[mcve]: https://stackoverflow.com/help/mcve
[template]: .github/PULL_REQUEST_TEMPLATE.md
### Triaging a Bug Report
Once an issue has been opened, it is not uncommon for there to be discussion
around it. Some contributors may have differing opinions about the issue,
including whether the behavior being seen is a bug or a feature. This discussion
is part of the process and should be kept focused, helpful, and professional.
Short, clipped responses—that provide neither additional context nor supporting
detail—are not helpful or professional. To many, such responses are simply
annoying and unfriendly.
Contributors are encouraged to help one another make forward progress as much as
possible, empowering one another to solve issues collaboratively. If you choose
to comment on an issue that you feel either is not a problem that needs to be
fixed, or if you encounter information in an issue that you feel is incorrect,
explain why you feel that way with additional supporting context, and be willing
to be convinced that you may be wrong. By doing so, we can often reach the
correct outcome much faster.
### Resolving a Bug Report
In the majority of cases, issues are resolved by opening a Pull Request. The
process for opening and reviewing a Pull Request is similar to that of opening
and triaging issues, but carries with it a necessary review and approval
workflow that ensures that the proposed changes meet the minimal quality and
functional guidelines of the Tokio project.
## Pull Requests
Pull Requests are the way concrete changes are made to the code, documentation,
and dependencies in the Tokio repository.
Even tiny pull requests (e.g., one character pull request fixing a typo in API
documentation) are greatly appreciated. Before making a large change, it is
usually a good idea to first open an issue describing the change to solicit
feedback and guidance. This will increase the likelihood of the PR getting
merged.
### Tests
If the change being proposed alters code (as opposed to only documentation for
example), it is either adding new functionality to Tokio or it is fixing
existing, broken functionality. In both of these cases, the pull request should
include one or more tests to ensure that Tokio does not regress in the future.
There are two ways to write tests: integration tests and documentation tests
(Tokio avoids unit tests as much as possible).
#### Integration tests
Integration tests go in the same crate as the code they are testing. Each sub
crate should have a `dev-dependency` on `tokio` itself. This makes all Tokio
utilities available to use in tests, no matter the crate being tested.
The best strategy for writing a new integration test is to look at existing
integration tests in the crate and follow the style.
#### Documentation tests
Ideally, every API has at least one [documentation test] that demonstrates how to
use the API. Documentation tests are run with `cargo test --doc`. This ensures
that the example is correct and provides additional test coverage.
The trick to documentation tests is striking a balance between being succinct
for a reader to understand and actually testing the API.
Same as with integration tests, when writing a documentation test, the full
`tokio` crate is available. This is especially useful for getting access to the
runtime to run the example.
The documentation tests will be visible from both the crate specific
documentation **and** the `tokio` facade documentation via the re-export. The
example should be written from the point of view of a user that is using the
`tokio` crate. As such, the example should use the API via the facade and not by
directly referencing the crate.
The type level example for `tokio_timer::Timeout` provides a good example of a
documentation test:
```
/// # extern crate futures;
/// # extern crate tokio;
/// // import the `timeout` function, usually this is done
/// // with `use tokio::prelude::*`
/// use tokio::prelude::FutureExt;
/// use futures::Stream;
/// use futures::sync::mpsc;
/// use std::time::Duration;
///
/// # fn main() {
/// let (tx, rx) = mpsc::unbounded();
/// # tx.unbounded_send(()).unwrap();
/// # drop(tx);
///
/// let process = rx.for_each(|item| {
/// // do something with `item`
/// # drop(item);
/// # Ok(())
/// });
///
/// # tokio::runtime::current_thread::block_on_all(
/// // Wrap the future with a `Timeout` set to expire in 10 milliseconds.
/// process.timeout(Duration::from_millis(10))
/// # ).unwrap();
/// # }
```
Given that this is a *type* level documentation test and the primary way users
of `tokio` will create an instance of `Timeout` is by using
`FutureExt::timeout`, this is how the documentation test is structured.
Lines that start with `/// #` are removed when the documentation is generated.
They are only there to get the test to run. The `block_on_all` function is the
easiest way to execute a future from a test.
If this were a documentation test for the `Timeout::new` function, then the
example would explicitly use `Timeout::new`. For example:
```
/// # extern crate futures;
/// # extern crate tokio;
/// use tokio::timer::Timeout;
/// use futures::Future;
/// use futures::sync::oneshot;
/// use std::time::Duration;
///
/// # fn main() {
/// let (tx, rx) = oneshot::channel();
/// # tx.send(()).unwrap();
///
/// # tokio::runtime::current_thread::block_on_all(
/// // Wrap the future with a `Timeout` set to expire in 10 milliseconds.
/// Timeout::new(rx, Duration::from_millis(10))
/// # ).unwrap();
/// # }
```
### Commits
It is a recommended best practice to keep your changes as logically grouped as
possible within individual commits. There is no limit to the number of commits
any single Pull Request may have, and many contributors find it easier to review
changes that are split across multiple commits.
That said, if you have a number of commits that are "checkpoints" and don't
represent a single logical change, please squash those together.
Note that multiple commits often get squashed when they are landed (see the
notes about [commit squashing]).
#### Commit message guidelines
A good commit message should describe what changed and why.
1. The first line should:
* contain a short description of the change (preferably 50 characters or less,
and no more than 72 characters)
* be entirely in lowercase with the exception of proper nouns, acronyms, and
the words that refer to code, like function/variable names
* be prefixed with the name of the sub crate being changed (without the `tokio-`
prefix) and start with an imperative verb. If modifying `tokio` proper,
omit the crate prefix.
Examples:
* timer: introduce `Timeout` and deprecate `Deadline`
* export `Encoder`, `Decoder`, `Framed*` from tokio_codec
2. Keep the second line blank.
3. Wrap all other lines at 72 columns (except for long URLs).
4. If your patch fixes an open issue, you can add a reference to it at the end
of the log. Use the `Fixes: #` prefix and the issue number. For other
references use `Refs: #`. `Refs` may include multiple issues, separated by a
comma.
Examples:
- `Fixes: #1337`
- `Refs: #1234`
Sample complete commit message:
```txt
subcrate: explain the commit in one line
Body of commit message is a few lines of text, explaining things
in more detail, possibly giving some background about the issue
being fixed, etc.
The body of the commit message can be several paragraphs, and
please do proper word-wrap and keep columns shorter than about
72 characters or so. That way, `git log` will show things
nicely even when it is indented.
Fixes: #1337
Refs: #453, #154
```
### Opening the Pull Request
From within GitHub, opening a new Pull Request will present you with a
[template] that should be filled out. Please try to do your best at filling out
the details, but feel free to skip parts if you're not sure what to put.
[template]: .github/PULL_REQUEST_TEMPLATE.md
### Discuss and update
You will probably get feedback or requests for changes to your Pull Request.
This is a big part of the submission process so don't be discouraged! Some
contributors may sign off on the Pull Request right away, others may have
more detailed comments or feedback. This is a necessary part of the process
in order to evaluate whether the changes are correct and necessary.
**Any community member can review a PR and you might get conflicting feedback**.
Keep an eye out for comments from code owners to provide guidance on conflicting
feedback.
**Once the PR is open, do not rebase the commits**. See [Commit Squashing] for
more details.
### Commit Squashing
In most cases, **do not squash commits that you add to your Pull Request during
the review process**. When the commits in your Pull Request land, they may be
squashed into one commit per logical change. Metadata will be added to the
commit message (including links to the Pull Request, links to relevant issues,
and the names of the reviewers). The commit history of your Pull Request,
however, will stay intact on the Pull Request page.
## Reviewing Pull Requests
**Any Tokio community member is welcome to review any pull request**.
All Tokio contributors who choose to review and provide feedback on Pull
Requests have a responsibility to both the project and the individual making the
contribution. Reviews and feedback must be helpful, insightful, and geared
towards improving the contribution as opposed to simply blocking it. If there
are reasons why you feel the PR should not land, explain what those are. Do not
expect to be able to block a Pull Request from advancing simply because you say
"No" without giving an explanation. Be open to having your mind changed. Be open
to working with the contributor to make the Pull Request better.
Reviews that are dismissive or disrespectful of the contributor or any other
reviewers are strictly counter to the Code of Conduct.
When reviewing a Pull Request, the primary goals are for the codebase to improve
and for the person submitting the request to succeed. **Even if a Pull Request
does not land, the submitters should come away from the experience feeling like
their effort was not wasted or unappreciated**. Every Pull Request from a new
contributor is an opportunity to grow the community.
### Review a bit at a time.
Do not overwhelm new contributors.
It is tempting to micro-optimize and make everything about relative performance,
perfect grammar, or exact style matches. Do not succumb to that temptation.
Focus first on the most significant aspects of the change:
1. Does this change make sense for Tokio?
2. Does this change make Tokio better, even if only incrementally?
3. Are there clear bugs or larger scale issues that need attending to?
4. Is the commit message readable and correct? If it contains a breaking change
is it clear enough?
Note that only **incremental** improvement is needed to land a PR. This means
that the PR does not need to be perfect, only better than the status quo. Follow
up PRs may be opened to continue iterating.
When changes are necessary, *request* them, do not *demand* them, and **do not
assume that the submitter already knows how to add a test or run a benchmark**.
Specific performance optimization techniques, coding styles and conventions
change over time. The first impression you give to a new contributor never does.
Nits (requests for small changes that are not essential) are fine, but try to
avoid stalling the Pull Request. Most nits can typically be fixed by the Tokio
Collaborator landing the Pull Request but they can also be an opportunity for
the contributor to learn a bit more about the project.
It is always good to clearly indicate nits when you comment: e.g.
`Nit: change foo() to bar(). But this is not blocking.`
If your comments were addressed but were not folded automatically after new
commits or if they proved to be mistaken, please, [hide them][hiding-a-comment]
with the appropriate reason to keep the conversation flow concise and relevant.
### Be aware of the person behind the code
Be aware that *how* you communicate requests and reviews in your feedback can
have a significant impact on the success of the Pull Request. Yes, we may land
a particular change that makes Tokio better, but the individual might just not
want to have anything to do with Tokio ever again. The goal is not just having
good code.
### Abandoned or Stalled Pull Requests
If a Pull Request appears to be abandoned or stalled, it is polite to first
check with the contributor to see if they intend to continue the work before
checking if they would mind if you took it over (especially if it just has nits
left). When doing so, it is courteous to give the original contributor credit
for the work they started (either by preserving their name and email address in
the commit log, or by using an `Author: ` meta-data tag in the commit.
_Adapted from the [Node.js contributing guide][node]_.
[node]: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md
[hiding-a-comment]: https://help.github.com/articles/managing-disruptive-comments/#hiding-a-comment
[documentation test]: https://doc.rust-lang.org/rustdoc/documentation-tests.html
+23
View File
@@ -0,0 +1,23 @@
[workspace]
members = [
"tokio",
"tokio-buf",
"tokio-codec",
"tokio-current-thread",
"tokio-executor",
"tokio-fs",
"tokio-futures",
"tokio-io",
"tokio-process",
"tokio-reactor",
"tokio-signal",
"tokio-sync",
"tokio-test",
"tokio-threadpool",
"tokio-timer",
"tokio-tcp",
"tokio-tls",
"tokio-udp",
"tokio-uds",
]
+25
View File
@@ -0,0 +1,25 @@
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.
+206
View File
@@ -0,0 +1,206 @@
# Tokio
A runtime for writing reliable, asynchronous, and slim applications with
the Rust programming language. It is:
* **Fast**: Tokio's zero-cost abstractions give you bare-metal
performance.
* **Reliable**: Tokio leverages Rust's ownership, type system, and
concurrency model to reduce bugs and ensure thread safety.
* **Scalable**: Tokio has a minimal footprint, and handles backpressure
and cancellation naturally.
[![Crates.io][crates-badge]][crates-url]
[![MIT licensed][mit-badge]][mit-url]
[![Build Status][azure-badge]][azure-url]
[![Gitter chat][gitter-badge]][gitter-url]
[crates-badge]: https://img.shields.io/crates/v/tokio.svg
[crates-url]: https://crates.io/crates/tokio
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
[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
[Website](https://tokio.rs) |
[Guides](https://tokio.rs/docs/getting-started/hello-world/) |
[API Docs](https://docs.rs/tokio/0.1.20/tokio) |
[Chat](https://gitter.im/tokio-rs/tokio)
The API docs for the master branch are published [here][master-dox].
[master-dox]: https://tokio-rs.github.io/tokio/doc/tokio/
## Overview
Tokio is an event-driven, non-blocking I/O platform for writing
asynchronous applications with the Rust programming language. At a high
level, it provides a few major components:
* A multithreaded, work-stealing based task [scheduler].
* A [reactor] backed by the operating system's event queue (epoll, kqueue,
IOCP, etc...).
* Asynchronous [TCP and UDP][net] sockets.
These components provide the runtime components necessary for building
an asynchronous application.
[net]: https://docs.rs/tokio/0.1.20/tokio/net/index.html
[reactor]: https://docs.rs/tokio/0.1.20/tokio/reactor/index.html
[scheduler]: https://docs.rs/tokio/0.1.20/tokio/runtime/index.html
## Example
A basic TCP echo server with Tokio:
```rust
extern crate tokio;
use tokio::prelude::*;
use tokio::io::copy;
use tokio::net::TcpListener;
fn main() {
// Bind the server's socket.
let addr = "127.0.0.1:12345".parse().unwrap();
let listener = TcpListener::bind(&addr)
.expect("unable to bind TCP listener");
// Pull out a stream of sockets for incoming connections
let server = listener.incoming()
.map_err(|e| eprintln!("accept failed = {:?}", e))
.for_each(|sock| {
// Split up the reading and writing parts of the
// socket.
let (reader, writer) = sock.split();
// A future that echos the data and returns how
// many bytes were copied...
let bytes_copied = copy(reader, writer);
// ... after which we'll print what happened.
let handle_conn = bytes_copied.map(|amt| {
println!("wrote {:?} bytes", amt)
}).map_err(|err| {
eprintln!("IO error {:?}", err)
});
// Spawn the future as a concurrent task.
tokio::spawn(handle_conn)
});
// Start the Tokio runtime
tokio::run(server);
}
```
More examples can be found [here](tokio/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.
[chat]: https://gitter.im/tokio-rs/tokio
[issue]: https://github.com/tokio-rs/tokio/issues/new
## Contributing
:balloon: Thanks for your help improving the project! We are so happy to have
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-current-thread`]: Schedule the execution of futures on the current
thread.
* [`tokio-executor`]: Task execution related traits and utilities.
* [`tokio-fs`]: Filesystem (and standard in / out) APIs.
* [`tokio-futures`]: Experimental `std::future::Future` and `async` / `await` support.
* [`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-reactor`]: Event loop that drives I/O resources (like TCP and UDP
sockets).
* [`tokio-tcp`]: TCP bindings for use with `tokio-io` and `tokio-reactor`.
* [`tokio-threadpool`]: Schedules the execution of futures across a pool of
threads.
* [ `tokio-timer`]: Time related APIs.
* [`tokio-udp`]: UDP bindings for use with `tokio-io` and `tokio-reactor`.
* [`tokio-uds`]: Unix Domain Socket bindings for use with `tokio-io` and
`tokio-reactor`.
[`tokio-codec`]: tokio-codec
[`tokio-current-thread`]: tokio-current-thread
[`tokio-executor`]: tokio-executor
[`tokio-fs`]: tokio-fs
[`tokio-futures`]: tokio-futures
[`tokio-io`]: tokio-io
[`tokio-macros`]: tokio-macros
[`tokio-reactor`]: tokio-reactor
[`tokio-tcp`]: tokio-tcp
[`tokio-threadpool`]: tokio-threadpool
[`tokio-timer`]: tokio-timer
[`tokio-udp`]: tokio-udp
[`tokio-uds`]: tokio-uds
## Related Projects
In addition to the crates in this repository, the Tokio project also maintains
several other libraries, including:
* [`tracing`] (formerly `tokio-trace`): A framework for application-level
tracing and async-aware diagnostics.
* [`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.
[`tracing`]: https://github.com/tokio-rs/tracing
[`mio`]: https://github.com/tokio-rs/mio
[`bytes`]: https://github.com/tokio-rs/bytes
## Supported Rust Versions
Tokio is built against the latest stable, nightly, and beta Rust releases. The
minimum version supported is the stable release from three months before the
current stable release version. For example, if the latest stable Rust is 1.29,
the minimum version supported is 1.26. The current Tokio version is not
guaranteed to build on Rust versions earlier than the minimum supported version.
## 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.
+104
View File
@@ -0,0 +1,104 @@
trigger: ["master", "v0.1.x"]
pr: ["master", "v0.1.x"]
jobs:
# Check formatting
- template: ci/azure-rustfmt.yml
parameters:
name: rustfmt
# Test top level crate
- template: ci/azure-test-stable.yml
parameters:
name: test_tokio
displayName: Test tokio
cross: true
crates:
- tokio
# Test crates that are platform specific
- template: ci/azure-test-stable.yml
parameters:
name: test_sub_cross
displayName: Test sub crates -
cross: true
crates:
- tokio-fs
- tokio-process
- tokio-reactor
- tokio-signal
- tokio-tcp
# - tokio-tls
- tokio-udp
- tokio-uds
# Test crates that are NOT platform specific
- template: ci/azure-test-stable.yml
parameters:
name: test_linux
displayName: Test sub crates -
crates:
- tokio-buf
- tokio-codec
- tokio-current-thread
- tokio-executor
- tokio-io
- tokio-sync
- tokio-threadpool
- tokio-timer
- tokio-test
- template: ci/azure-cargo-check.yml
parameters:
name: features
displayName: Check feature permtuations
rust: stable
crates:
tokio:
- codec
- fs
- io
- reactor
- rt-full
- tcp
- timer
- udp
- uds
- sync
- experimental-tracing
tokio-buf:
- util
# 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.31.0
- template: ci/azure-tsan.yml
parameters:
name: tsan
- template: ci/azure-deploy-docs.yml
parameters:
dependsOn:
- rustfmt
- test_tokio
- test_sub_cross
- test_linux
- features
- cross_32bit_linux
- minrust
- tsan
+114
View File
@@ -0,0 +1,114 @@
#![feature(test)]
extern crate test;
#[macro_use]
extern crate futures;
extern crate tokio;
use std::io;
use std::net::SocketAddr;
use std::thread;
use futures::sync::mpsc;
use futures::sync::oneshot;
use futures::{Future, Poll, Sink, Stream};
use test::Bencher;
use tokio::net::UdpSocket;
/// UDP echo server
struct EchoServer {
socket: UdpSocket,
buf: Vec<u8>,
to_send: Option<(usize, SocketAddr)>,
}
impl EchoServer {
fn new(s: UdpSocket) -> Self {
EchoServer {
socket: s,
to_send: None,
buf: vec![0u8; 1600],
}
}
}
impl Future for EchoServer {
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<(), io::Error> {
loop {
if let Some(&(size, peer)) = self.to_send.as_ref() {
try_ready!(self.socket.poll_send_to(&self.buf[..size], &peer));
self.to_send = None;
}
self.to_send = Some(try_ready!(self.socket.poll_recv_from(&mut self.buf)));
}
}
}
#[bench]
fn udp_echo_latency(b: &mut Bencher) {
let any_addr = "127.0.0.1:0".to_string();
let any_addr = any_addr.parse::<SocketAddr>().unwrap();
let (stop_c, stop_p) = oneshot::channel::<()>();
let (tx, rx) = oneshot::channel();
let child = thread::spawn(move || {
let socket = tokio::net::UdpSocket::bind(&any_addr).unwrap();
tx.send(socket.local_addr().unwrap()).unwrap();
let server = EchoServer::new(socket);
let server = server.select(stop_p.map_err(|_| panic!()));
let server = server.map_err(|_| ());
server.wait().unwrap();
});
let client = std::net::UdpSocket::bind(&any_addr).unwrap();
let server_addr = rx.wait().unwrap();
let mut buf = [0u8; 1000];
// warmup phase; for some reason initial couple of
// runs are much slower
//
// TODO: Describe the exact reasons; caching? branch predictor? lazy closures?
for _ in 0..8 {
client.send_to(&buf, &server_addr).unwrap();
let _ = client.recv_from(&mut buf).unwrap();
}
b.iter(|| {
client.send_to(&buf, &server_addr).unwrap();
let _ = client.recv_from(&mut buf).unwrap();
});
stop_c.send(()).unwrap();
child.join().unwrap();
}
#[bench]
fn futures_channel_latency(b: &mut Bencher) {
let (mut in_tx, in_rx) = mpsc::channel(32);
let (out_tx, out_rx) = mpsc::channel::<_>(32);
let child = thread::spawn(|| out_tx.send_all(in_rx.then(|r| r.unwrap())).wait());
let mut rx_iter = out_rx.wait();
// warmup phase; for some reason initial couple of runs are much slower
//
// TODO: Describe the exact reasons; caching? branch predictor? lazy closures?
for _ in 0..8 {
in_tx.start_send(Ok(1usize)).unwrap();
let _ = rx_iter.next();
}
b.iter(|| {
in_tx.start_send(Ok(1usize)).unwrap();
let _ = rx_iter.next();
});
drop(in_tx);
child.join().unwrap().unwrap();
}
+56
View File
@@ -0,0 +1,56 @@
// Measure cost of different operations
// to get a sense of performance tradeoffs
#![feature(test)]
extern crate mio;
extern crate test;
use test::Bencher;
use mio::tcp::TcpListener;
use mio::{PollOpt, Ready, Token};
#[bench]
fn mio_register_deregister(b: &mut Bencher) {
let addr = "127.0.0.1:0".parse().unwrap();
// Setup the server socket
let sock = TcpListener::bind(&addr).unwrap();
let poll = mio::Poll::new().unwrap();
const CLIENT: Token = Token(1);
b.iter(|| {
poll.register(&sock, CLIENT, Ready::readable(), PollOpt::edge())
.unwrap();
poll.deregister(&sock).unwrap();
});
}
#[bench]
fn mio_reregister(b: &mut Bencher) {
let addr = "127.0.0.1:0".parse().unwrap();
// Setup the server socket
let sock = TcpListener::bind(&addr).unwrap();
let poll = mio::Poll::new().unwrap();
const CLIENT: Token = Token(1);
poll.register(&sock, CLIENT, Ready::readable(), PollOpt::edge())
.unwrap();
b.iter(|| {
poll.reregister(&sock, CLIENT, Ready::readable(), PollOpt::edge())
.unwrap();
});
poll.deregister(&sock).unwrap();
}
#[bench]
fn mio_poll(b: &mut Bencher) {
let poll = mio::Poll::new().unwrap();
let timeout = std::time::Duration::new(0, 0);
let mut events = mio::Events::with_capacity(1024);
b.iter(|| {
poll.poll(&mut events, Some(timeout)).unwrap();
});
}
+260
View File
@@ -0,0 +1,260 @@
#![feature(test)]
extern crate futures;
extern crate tokio;
#[macro_use]
extern crate tokio_io;
pub extern crate test;
mod prelude {
pub use futures::*;
pub use tokio::net::{TcpListener, TcpStream};
pub use tokio::reactor::Reactor;
pub use tokio_io::io::read_to_end;
pub use std::io::{self, Read, Write};
pub use std::thread;
pub use std::time::Duration;
pub use test::{self, Bencher};
}
mod connect_churn {
use prelude::*;
const NUM: usize = 300;
const CONCURRENT: usize = 8;
#[bench]
fn one_thread(b: &mut Bencher) {
let addr = "127.0.0.1:0".parse().unwrap();
b.iter(move || {
let listener = TcpListener::bind(&addr).unwrap();
let addr = listener.local_addr().unwrap();
// Spawn a single future that accepts & drops connections
let serve_incomings = listener
.incoming()
.map_err(|e| panic!("server err: {:?}", e))
.for_each(|_| Ok(()));
let connects = stream::iter_result((0..NUM).map(|_| {
Ok(TcpStream::connect(&addr).and_then(|sock| {
sock.set_linger(Some(Duration::from_secs(0))).unwrap();
read_to_end(sock, vec![])
}))
}));
let connects_concurrent = connects
.buffer_unordered(CONCURRENT)
.map_err(|e| panic!("client err: {:?}", e))
.for_each(|_| Ok(()));
serve_incomings
.select(connects_concurrent)
.map(|_| ())
.map_err(|_| ())
.wait()
.unwrap();
});
}
fn n_workers(n: usize, b: &mut Bencher) {
let (shutdown_tx, shutdown_rx) = sync::oneshot::channel();
let (addr_tx, addr_rx) = sync::oneshot::channel();
// Spawn reactor thread
let server_thread = thread::spawn(move || {
// Bind the TCP listener
let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
// Get the address being listened on.
let addr = listener.local_addr().unwrap();
// Send the remote & address back to the main thread
addr_tx.send(addr).unwrap();
// Spawn a single future that accepts & drops connections
let serve_incomings = listener
.incoming()
.map_err(|e| panic!("server err: {:?}", e))
.for_each(|_| Ok(()));
// Run server
serve_incomings
.select(shutdown_rx)
.map(|_| ())
.map_err(|_| ())
.wait()
.unwrap();
});
// Get the bind addr of the server
let addr = addr_rx.wait().unwrap();
b.iter(move || {
use std::sync::{Arc, Barrier};
// Create a barrier to coordinate threads
let barrier = Arc::new(Barrier::new(n + 1));
// Spawn worker threads
let threads: Vec<_> = (0..n)
.map(|_| {
let barrier = barrier.clone();
let addr = addr.clone();
thread::spawn(move || {
let connects = stream::iter_result((0..(NUM / n)).map(|_| {
Ok(TcpStream::connect(&addr)
.map_err(|e| panic!("connect err: {:?}", e))
.and_then(|sock| {
sock.set_linger(Some(Duration::from_secs(0))).unwrap();
read_to_end(sock, vec![])
}))
}));
barrier.wait();
connects
.buffer_unordered(CONCURRENT)
.map_err(|e| panic!("client err: {:?}", e))
.for_each(|_| Ok(()))
.wait()
.unwrap();
})
})
.collect();
barrier.wait();
for th in threads {
th.join().unwrap();
}
});
// Shutdown the server
shutdown_tx.send(()).unwrap();
server_thread.join().unwrap();
}
#[bench]
fn two_threads(b: &mut Bencher) {
n_workers(1, b);
}
#[bench]
fn multi_threads(b: &mut Bencher) {
n_workers(4, b);
}
}
mod transfer {
use prelude::*;
use std::{cmp, mem};
const MB: usize = 3 * 1024 * 1024;
struct Drain {
sock: TcpStream,
chunk: usize,
}
impl Future for Drain {
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<(), io::Error> {
let mut buf: [u8; 1024] = unsafe { mem::uninitialized() };
loop {
match try_nb!(self.sock.read(&mut buf[..self.chunk])) {
0 => return Ok(Async::Ready(())),
_ => {}
}
}
}
}
struct Transfer {
sock: TcpStream,
rem: usize,
chunk: usize,
}
impl Future for Transfer {
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<(), io::Error> {
while self.rem > 0 {
let len = cmp::min(self.rem, self.chunk);
let buf = &DATA[..len];
let n = try_nb!(self.sock.write(&buf));
self.rem -= n;
}
Ok(Async::Ready(()))
}
}
static DATA: [u8; 1024] = [0; 1024];
fn one_thread(b: &mut Bencher, read_size: usize, write_size: usize) {
let addr = "127.0.0.1:0".parse().unwrap();
b.iter(move || {
let listener = TcpListener::bind(&addr).unwrap();
let addr = listener.local_addr().unwrap();
// Spawn a single future that accepts 1 connection, Drain it and drops
let server = listener
.incoming()
.into_future() // take the first connection
.map_err(|(e, _other_incomings)| e)
.map(|(connection, _other_incomings)| connection.unwrap())
.and_then(|sock| {
sock.set_linger(Some(Duration::from_secs(0))).unwrap();
let drain = Drain {
sock: sock,
chunk: read_size,
};
drain
.map(|_| ())
.map_err(|e| panic!("server error: {:?}", e))
})
.map_err(|e| panic!("server err: {:?}", e));
let client = TcpStream::connect(&addr)
.and_then(move |sock| Transfer {
sock: sock,
rem: MB,
chunk: write_size,
})
.map_err(|e| panic!("client err: {:?}", e));
server.join(client).wait().unwrap();
});
}
mod small_chunks {
use prelude::*;
#[bench]
fn one_thread(b: &mut Bencher) {
super::one_thread(b, 32, 32);
}
}
mod big_chunks {
use prelude::*;
#[bench]
fn one_thread(b: &mut Bencher) {
super::one_thread(b, 1_024, 1_024);
}
}
}
+29
View File
@@ -0,0 +1,29 @@
parameters:
noDefaultFeatures: '--no-default-features'
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
pool:
vmImage: ubuntu-16.04
steps:
- template: azure-install-rust.yml
parameters:
rust_version: ${{ parameters.rust }}
- template: azure-is-release.yml
- ${{ each crate in parameters.crates }}:
- ${{ each feature in crate.value }}:
- script: cargo check ${{ parameters.noDefaultFeatures }} --features ${{ feature }}
displayName: Check `${{ crate.key }}`, features = ${{ feature }}
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
condition: and(succeeded(), not(variables['isRelease']))
- template: azure-patch-crates.yml
- ${{ each crate in parameters.crates }}:
- ${{ each feature in crate.value }}:
- script: cargo check ${{ parameters.noDefaultFeatures }} --features ${{ feature }}
displayName: Check `${{ crate.key }}`, features = ${{ feature }}
workingDirectory: $(Build.SourcesDirectory)/${{ crate.key }}
+14
View File
@@ -0,0 +1,14 @@
jobs:
- job: ${{ parameters.name }}
displayName: Min supported Rust version
pool:
vmImage: ubuntu-16.04
steps:
- template: azure-install-rust.yml
parameters:
rust_version: ${{ parameters.rust_version }}
- template: azure-patch-crates.yml
- script: cargo check --all
displayName: cargo check --all
+27
View File
@@ -0,0 +1,27 @@
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
pool:
vmImage: ubuntu-16.04
steps:
- template: azure-install-rust.yml
parameters:
rust_version: stable
- script: sudo apt-get update
displayName: "apt-get update"
- script: sudo apt-get install gcc-multilib
displayName: "Install gcc-multilib"
- script: rustup target add ${{ parameters.target }}
displayName: "Add target"
# Always patch
- template: azure-patch-crates.yml
- script: cargo check --all --exclude tokio-tls --target ${{ parameters.target }}
displayName: Check source
- script: cargo check --tests --all --exclude tokio-tls --target ${{ parameters.target }}
displayName: Check tests
+38
View File
@@ -0,0 +1,38 @@
parameters:
dependsOn: []
jobs:
- job: documentation
displayName: 'Deploy API Documentation'
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
pool:
vmImage: 'Ubuntu 16.04'
dependsOn:
- ${{ parameters.dependsOn }}
steps:
- template: azure-install-rust.yml
parameters:
rust_version: stable
- script: |
cargo doc --all --no-deps
cp -R target/doc '$(Build.BinariesDirectory)'
displayName: 'Generate Documentation'
- script: |
set -e
git --version
ls -la
git init
git config user.name 'Deployment Bot (from Azure Pipelines)'
git config user.email '[email protected]'
git config --global credential.helper 'store --file ~/.my-credentials'
printf "protocol=https\nhost=github.com\nusername=carllerche\npassword=%s\n\n" "$GITHUB_TOKEN" | git credential-store --file ~/.my-credentials store
git remote add origin https://github.com/tokio-rs/tokio
git checkout -b gh-pages
git add .
git commit -m 'Deploy Tokio API documentation'
git push -f origin gh-pages
env:
GITHUB_TOKEN: $(githubPersonalToken)
workingDirectory: '$(Build.BinariesDirectory)'
displayName: 'Deploy Documentation'
+33
View File
@@ -0,0 +1,33 @@
steps:
# Linux and macOS.
- script: |
set -e
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none
export PATH=$PATH:$HOME/.cargo/bin
rustup toolchain install $RUSTUP_TOOLCHAIN
rustup default $RUSTUP_TOOLCHAIN
echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin"
env:
RUSTUP_TOOLCHAIN: ${{parameters.rust_version}}
displayName: "Install rust (*nix)"
condition: not(eq(variables['Agent.OS'], 'Windows_NT'))
# Windows.
- script: |
echo "windows"
curl -sSf -o rustup-init.exe https://win.rustup.rs
rustup-init.exe -y --default-toolchain none
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
rustup toolchain install %RUSTUP_TOOLCHAIN%
rustup default %RUSTUP_TOOLCHAIN%
echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin"
env:
RUSTUP_TOOLCHAIN: ${{parameters.rust_version}}
displayName: Install rust (windows)
condition: eq(variables['Agent.OS'], 'Windows_NT')
# All platforms.
- script: |
rustc -Vv
cargo -V
displayName: Query rust and cargo versions
+9
View File
@@ -0,0 +1,9 @@
steps:
- bash: |
set -e
if git log --no-merges -1 --format='%B' | grep -qF '[ci-release]'; then
echo "##vso[task.setvariable variable=isRelease]true"
fi
failOnStderr: true
displayName: Check if release commit
+16
View File
@@ -0,0 +1,16 @@
steps:
- script: |
set -e
# Remove any existing patch statements
mv Cargo.toml Cargo.toml.bck
sed -n '/\[patch.crates-io\]/q;p' Cargo.toml.bck > Cargo.toml
# Patch all crates
cat ci/patch.toml >> Cargo.toml
# Print `Cargo.toml` for debugging
echo "~~~~ Cargo.toml ~~~~"
cat Cargo.toml
echo "~~~~~~~~~~~~~~~~~~~~"
displayName: Patch Cargo.toml
+16
View File
@@ -0,0 +1,16 @@
jobs:
# Check formatting
- job: ${{ parameters.name }}
displayName: Check rustfmt
pool:
vmImage: ubuntu-16.04
steps:
- template: azure-install-rust.yml
parameters:
rust_version: stable
- script: |
rustup component add rustfmt
displayName: Install rustfmt
- script: |
cargo fmt --all -- --check
displayName: Check formatting
+41
View File
@@ -0,0 +1,41 @@
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
strategy:
matrix:
Linux:
vmImage: ubuntu-16.04
${{ if parameters.cross }}:
MacOS:
vmImage: macOS-10.14
Windows:
vmImage: vs2017-win2016
pool:
vmImage: $(vmImage)
steps:
- template: azure-install-rust.yml
parameters:
rust_version: stable
- template: azure-is-release.yml
- ${{ each crate in parameters.crates }}:
- script: cargo test
env:
LOOM_MAX_DURATION: 10
CI: 'True'
displayName: cargo test -p ${{ crate }}
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
condition: and(succeeded(), ne(variables['isRelease'], 'true'))
- template: azure-patch-crates.yml
- ${{ each crate in parameters.crates }}:
- script: cargo test
env:
LOOM_MAX_DURATION: 10
CI: 'True'
displayName: cargo test -p ${{ crate }} (PATCHED)
workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
+36
View File
@@ -0,0 +1,36 @@
jobs:
- job: ${{ parameters.name }}
displayName: TSAN
strategy:
matrix:
Timer:
cmd: cargo test -p tokio-timer --test hammer
Threadpool:
cmd: cargo test -p tokio-threadpool --tests
pool:
vmImage: ubuntu-16.04
steps:
- template: azure-install-rust.yml
parameters:
rust_version: nightly-2019-07-17
- template: azure-patch-crates.yml
- script: |
set -e
# Make sure the benchmarks compile
export ASAN_OPTIONS="detect_odr_violation=0 detect_leaks=0"
export TSAN_OPTIONS="suppressions=`pwd`/ci/tsan"
export RUST_BACKTRACE=1
# Run address sanitizer
RUSTFLAGS="-Z sanitizer=address" \
$(cmd) --target x86_64-unknown-linux-gnu
# Run thread sanitizer
RUSTFLAGS="-Z sanitizer=thread" \
$(cmd) --target x86_64-unknown-linux-gnu
displayName: TSAN / MSAN
env:
TSAN: yes
+20
View File
@@ -0,0 +1,20 @@
# Patch dependencies to run all tests against versions of the crate in the
# repository.
[patch.crates-io]
tokio = { path = "tokio" }
tokio-buf = { path = "tokio-buf" }
tokio-codec = { path = "tokio-codec" }
tokio-current-thread = { path = "tokio-current-thread" }
tokio-executor = { path = "tokio-executor" }
tokio-fs = { path = "tokio-fs" }
tokio-futures = { path = "tokio-futures" }
tokio-io = { path = "tokio-io" }
tokio-reactor = { path = "tokio-reactor" }
tokio-signal = { path = "tokio-signal" }
tokio-sync = { path = "tokio-sync" }
tokio-threadpool = { path = "tokio-threadpool" }
tokio-timer = { path = "tokio-timer" }
tokio-tcp = { path = "tokio-tcp" }
tokio-tls = { path = "tokio-tls" }
tokio-udp = { path = "tokio-udp" }
tokio-uds = { path = "tokio-uds" }
+44
View File
@@ -0,0 +1,44 @@
# TSAN suppressions file for Tokio
# TSAN does not understand fences and `Arc::drop` is implemented using a fence.
# This causes many false positives.
race:Arc*drop
race:Weak*drop
# `std` mpsc is not used in any Tokio code base. This race is triggered by some
# rust runtime logic.
race:std*mpsc_queue
# Probably more fences in std.
race:__call_tls_dtors
# The epoch-based GC uses fences.
race:crossbeam_epoch
# Push and steal operations in crossbeam-deque may cause data races, but such
# data races are safe. If a data race happens, the value read by `steal` is
# forgotten and the steal operation is then retried.
race:crossbeam_deque*push
race:crossbeam_deque*steal
# This filters out expected data race in the Treiber stack implementations.
# Treiber stacks are inherently racy. The pop operation will attempt to access
# the "next" pointer on the node it is attempting to pop. However, at this
# point it has not gained ownership of the node and another thread might beat
# it and take ownership of the node first (touching the next pointer). The
# original pop operation will fail due to the ABA guard, but tsan still picks
# up the access on the next pointer.
race:Backup::next_sleeper
race:Backup::set_next_sleeper
race:WorkerEntry::set_next_sleeper
# This ignores a false positive caused by `thread::park()`/`thread::unpark()`.
# See: https://github.com/rust-lang/rust/pull/54806#issuecomment-436193353
race:pthread_cond_destroy
# Recent rand dependency updates and seeding changes have introduced
# lazy_static's and other racy code. See:
# https://github.com/tokio-rs/tokio/pull/1358#issuecomment-516172383
race:RandomState*::build_hasher
race:lazy_static::
race:c2_chacha::guts
+14
View File
@@ -0,0 +1,14 @@
# 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
+32
View File
@@ -0,0 +1,32 @@
[package]
name = "tokio-buf"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.1"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-buf/0.1.1/tokio_buf"
description = """
Asynchronous stream of byte buffers
"""
categories = ["asynchronous"]
[dependencies]
bytes = "0.4.10"
either = { version = "1.5", optional = true}
futures = "0.1.23"
[features]
default = ["util"]
util = ["bytes/either", "either"]
[dev-dependencies]
tokio-mock-task = "0.1.1"
+25
View File
@@ -0,0 +1,25 @@
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.
+37
View File
@@ -0,0 +1,37 @@
# tokio-buf
Asynchronous stream of byte buffers
> **Note:** This crate has been **deprecated in tokio 0.2.x**.
[Documenation](https://docs.rs/tokio-buf)
## Usage
First, add this to your `Cargo.toml`:
```toml
[dependencies]
tokio-buf = "0.1.1"
```
Next, add this to your crate:
```rust
extern crate tokio_buf;
```
You can find extensive documentation and examples about how to use this crate
online at [https://tokio.rs](https://tokio.rs). The [API
documentation](https://docs.rs/tokio-buf) is also a great place to get started
for the nitty-gritty.
## 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.
+100
View File
@@ -0,0 +1,100 @@
#![doc(html_root_url = "https://docs.rs/tokio-buf/0.1.1")]
#![deny(missing_docs, missing_debug_implementations, unreachable_pub)]
//! Asynchronous stream of bytes.
//!
//! > **Note:** This crate has been **deprecated in tokio 0.2.x**.
//!
//! 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).
extern crate bytes;
#[cfg(feature = "util")]
extern crate either;
#[allow(unused)]
#[macro_use]
extern crate futures;
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 util::BufStreamExt;
use bytes::Buf;
use futures::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:
///
/// - `Ok(Async::NotReady)` 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.
///
/// - `Ok(Async::Ready(Some(buf)))` means that the stream has successfully
/// produced a value, `buf`, and may produce further values on subsequent
/// `poll_buf` calls.
///
/// - `Ok(Async::Ready(None))` means that the stream has terminated, and
/// `poll_buf` should not be invoked again.
///
/// # Panics
///
/// Once a stream is finished, i.e. `Ready(None)` has been returned, further
/// calls to `poll_buf` may result in a panic or other "bad behavior".
fn poll_buf(&mut self) -> Poll<Option<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()
}
}
+22
View File
@@ -0,0 +1,22 @@
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 {
fn description(&self) -> &str {
match *self {}
}
}
+56
View File
@@ -0,0 +1,56 @@
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
@@ -0,0 +1,55 @@
use never::Never;
use BufStream;
use 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
@@ -0,0 +1,66 @@
use bytes::{Bytes, BytesMut};
use futures::Poll;
use never::Never;
use std::io;
use BufStream;
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
@@ -0,0 +1,46 @@
use BufStream;
use either::Either;
use futures::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
@@ -0,0 +1,101 @@
use super::FromBufStream;
use BufStream;
use futures::{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,
}
}
}
+162
View File
@@ -0,0 +1,162 @@
use 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 {
fn description(&self) -> &str {
"BufStream too big"
}
}
impl fmt::Display for CollectBytesError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "BufStream too big")
}
}
impl Error for CollectBytesError {
fn description(&self) -> &str {
"BufStream too big"
}
}
+54
View File
@@ -0,0 +1,54 @@
use bytes::Buf;
use futures::Poll;
use std::error::Error;
use std::fmt;
use BufStream;
/// 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 {
fn description(&self) -> &str {
unreachable!();
}
}
+76
View File
@@ -0,0 +1,76 @@
use 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
@@ -0,0 +1,87 @@
//! 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 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
@@ -0,0 +1,76 @@
use bytes::Buf;
use futures::{Async, Poll, Stream};
use BufStream;
/// 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),
}
}
}
+7
View File
@@ -0,0 +1,7 @@
extern crate tokio_buf;
use tokio_buf::BufStream;
// Ensures that `BufStream` can be a trait object
#[allow(dead_code)]
fn obj(_: &mut dyn BufStream<Item = u32, Error = ()>) {}
+43
View File
@@ -0,0 +1,43 @@
#![cfg(feature = "util")]
extern crate bytes;
extern crate futures;
extern crate tokio_buf;
use futures::Async::*;
use tokio_buf::{BufStream, BufStreamExt};
#[macro_use]
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());
}
+68
View File
@@ -0,0 +1,68 @@
#![cfg(feature = "util")]
extern crate bytes;
extern crate futures;
extern crate tokio_buf;
use bytes::Bytes;
use futures::Future;
use tokio_buf::BufStreamExt;
#[macro_use]
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);
}
+33
View File
@@ -0,0 +1,33 @@
extern crate bytes;
extern crate futures;
extern crate tokio_buf;
use futures::Async::*;
use std::io::Cursor;
use tokio_buf::{util, BufStream};
#[macro_use]
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)
}
+65
View File
@@ -0,0 +1,65 @@
#![cfg(feature = "util")]
extern crate bytes;
extern crate futures;
extern crate tokio_buf;
use futures::Async::*;
use futures::Future;
use tokio_buf::{BufStream, BufStreamExt};
#[macro_use]
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());
}
+42
View File
@@ -0,0 +1,42 @@
extern crate tokio_buf;
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);
}
+49
View File
@@ -0,0 +1,49 @@
extern crate bytes;
extern crate futures;
extern crate tokio_buf;
extern crate tokio_mock_task;
use futures::sync::mpsc;
use futures::Async::*;
use std::io::Cursor;
use tokio_buf::{util, BufStream};
use tokio_mock_task::MockTask;
#[macro_use]
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)
}
+38
View File
@@ -0,0 +1,38 @@
extern crate bytes;
extern crate futures;
extern crate tokio_buf;
use futures::Async::*;
use std::fmt;
use tokio_buf::BufStream;
#[macro_use]
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
@@ -0,0 +1,133 @@
#![allow(unused)]
extern crate bytes;
extern crate futures;
extern crate tokio_buf;
use bytes::Buf;
use futures::Async::*;
use futures::Poll;
use tokio_buf::{BufStream, SizeHint};
use std::collections::VecDeque;
use std::io::Cursor;
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_rules! assert_none {
($actual:expr) => {
match $actual {
Ok(Ready(None)) => {}
actual => panic!("expected None; actual = {:?}", actual),
}
};
}
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)
}
}
+11
View File
@@ -0,0 +1,11 @@
# 0.1.2 (February 4, 2020)
* Add `tokio 0.2.x` deprecation notice.
# 0.1.1 (September 26, 2018)
* Allow setting max line length with `LinesCodec` (#632)
# 0.1.0 (June 13, 2018)
* Initial release (#353)
+25
View File
@@ -0,0 +1,25 @@
[package]
name = "tokio-codec"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.2"
authors = ["Carl Lerche <[email protected]>", "Bryan Burgers <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-codec/0.1.2/tokio_codec"
description = """
Utilities for encoding and decoding frames.
"""
categories = ["asynchronous"]
[dependencies]
tokio-io = "0.1.7"
bytes = "0.4.7"
futures = "0.1.18"
+25
View File
@@ -0,0 +1,25 @@
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.
+42
View File
@@ -0,0 +1,42 @@
# tokio-codec
Utilities for encoding and decoding frames.
> **Note:** This crate is **deprecated in tokio 0.2.x** and has been moved into
> [`tokio_util::codec`] of the [`tokio-util` crate] behind the `codec` feature
> flag.
[`tokio_util::codec`]: https://docs.rs/tokio-util/latest/tokio_util/codec/index.html
[`tokio-util` crate]: https://docs.rs/tokio-util/latest/tokio_util
[Documentation](https://docs.rs/tokio-codec)
## Usage
First, add this to your `Cargo.toml`:
```toml
[dependencies]
tokio-codec = "0.1"
```
Next, add this to your crate:
```rust
extern crate tokio_codec;
```
You can find extensive documentation and examples about how to use this crate
online at [https://tokio.rs](https://tokio.rs). The [API
documentation](https://docs.rs/tokio-codec) is also a great place to get started
for the nitty-gritty.
## 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.
+39
View File
@@ -0,0 +1,39 @@
use bytes::{BufMut, Bytes, BytesMut};
use std::io;
use tokio_io::_tokio_codec::{Decoder, Encoder};
/// A simple `Codec` implementation that just ships bytes around.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
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.len() > 0 {
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(())
}
}
+32
View File
@@ -0,0 +1,32 @@
#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-codec/0.1.2")]
//! Utilities for encoding and decoding frames.
//!
//! > **Note:** This crate is **deprecated in tokio 0.2.x** and has been moved
//! into [`tokio_util::codec`] of the [`tokio-util` crate] behind the `codec`
//! feature flag.
//!
//! [`tokio_util::codec`]: https://docs.rs/tokio-util/latest/tokio_util/codec/index.html
//! [`tokio-util` crate]: https://docs.rs/tokio-util/latest/tokio_util
//!
//! 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`]: #
//! [`AsyncWrite`]: #
//! [`Sink`]: #
//! [`Stream`]: #
//! [transports]: #
extern crate bytes;
extern crate tokio_io;
mod bytes_codec;
mod lines_codec;
pub use tokio_io::_tokio_codec::{Decoder, Encoder, Framed, FramedParts, FramedRead, FramedWrite};
pub use bytes_codec::BytesCodec;
pub use lines_codec::LinesCodec;
+195
View File
@@ -0,0 +1,195 @@
use bytes::{BufMut, BytesMut};
use std::{cmp, io, str, usize};
use tokio_io::_tokio_codec::{Decoder, Encoder};
/// A simple `Codec` implementation that splits up data into lines.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct LinesCodec {
// Stored index of the next index to examine for a `\n` character.
// This is used to optimize searching.
// For example, if `decode` was called with `abc`, it would hold `3`,
// because that is the next index to examine.
// The next time `decode` is called with `abcde\n`, the method will
// only look at `de\n` before returning.
next_index: usize,
/// The maximum length for a given line. If `usize::MAX`, lines will be
/// read until a `\n` character is reached.
max_length: usize,
/// Are we currently discarding the remainder of a line which was over
/// the length limit?
is_discarding: bool,
}
impl LinesCodec {
/// Returns a `LinesCodec` for splitting up data into lines.
///
/// # Note
///
/// The returned `LinesCodec` will not have an upper bound on the length
/// of a buffered line. See the documentation for [`new_with_max_length`]
/// for information on why this could be a potential security risk.
///
/// [`new_with_max_length`]: #method.new_with_max_length
pub fn new() -> LinesCodec {
LinesCodec {
next_index: 0,
max_length: usize::MAX,
is_discarding: false,
}
}
/// Returns a `LinesCodec` with a maximum line length limit.
///
/// If this is set, calls to `LinesCodec::decode` will return a
/// [`LengthError`] when a line exceeds the length limit. Subsequent calls
/// will discard up to `limit` bytes from that line until a newline
/// character is reached, returning `None` until the line over the limit
/// has been fully discarded. After that point, calls to `decode` will
/// function as normal.
///
/// # Note
///
/// Setting a length limit is highly recommended for any `LinesCodec` which
/// will be exposed to untrusted input. Otherwise, the size of the buffer
/// that holds the line currently being read is unbounded. An attacker could
/// exploit this unbounded buffer by sending an unbounded amount of input
/// without any `\n` characters, causing unbounded memory consumption.
///
/// [`LengthError`]: ../struct.LengthError
pub fn new_with_max_length(max_length: usize) -> Self {
LinesCodec {
max_length,
..LinesCodec::new()
}
}
/// Returns the maximum line length when decoding.
///
/// ```
/// use std::usize;
/// use tokio_codec::LinesCodec;
///
/// let codec = LinesCodec::new();
/// assert_eq!(codec.max_length(), usize::MAX);
/// ```
/// ```
/// use tokio_codec::LinesCodec;
///
/// let codec = LinesCodec::new_with_max_length(256);
/// assert_eq!(codec.max_length(), 256);
/// ```
pub fn max_length(&self) -> usize {
self.max_length
}
fn discard(&mut self, newline_offset: Option<usize>, read_to: usize, buf: &mut BytesMut) {
let discard_to = if let Some(offset) = newline_offset {
// If we found a newline, discard up to that offset and
// then stop discarding. On the next iteration, we'll try
// to read a line normally.
self.is_discarding = false;
offset + self.next_index + 1
} else {
// Otherwise, we didn't find a newline, so we'll discard
// everything we read. On the next iteration, we'll continue
// discarding up to max_len bytes unless we find a newline.
read_to
};
buf.advance(discard_to);
self.next_index = 0;
}
}
fn utf8(buf: &[u8]) -> Result<&str, io::Error> {
str::from_utf8(buf)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Unable to decode input as UTF8"))
}
fn without_carriage_return(s: &[u8]) -> &[u8] {
if let Some(&b'\r') = s.last() {
&s[..s.len() - 1]
} else {
s
}
}
impl Decoder for LinesCodec {
type Item = String;
// TODO: in the next breaking change, this should be changed to a custom
// error type that indicates the "max length exceeded" condition better.
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<String>, io::Error> {
loop {
// Determine how far into the buffer we'll search for a newline. If
// there's no max_length set, we'll read to the end of the buffer.
let read_to = cmp::min(self.max_length.saturating_add(1), buf.len());
let newline_offset = buf[self.next_index..read_to]
.iter()
.position(|b| *b == b'\n');
if self.is_discarding {
self.discard(newline_offset, read_to, buf);
} else {
return if let Some(offset) = newline_offset {
// Found a line!
let newline_index = offset + self.next_index;
self.next_index = 0;
let line = buf.split_to(newline_index + 1);
let line = &line[..line.len() - 1];
let line = without_carriage_return(line);
let line = utf8(line)?;
Ok(Some(line.to_string()))
} else if buf.len() > self.max_length {
// Reached the maximum length without finding a
// newline, return an error and start discarding on the
// next call.
self.is_discarding = true;
Err(io::Error::new(
io::ErrorKind::Other,
"line length limit exceeded",
))
} else {
// We didn't find a line or reach the length limit, so the next
// call will resume searching at the current offset.
self.next_index = read_to;
Ok(None)
};
}
}
}
fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<String>, io::Error> {
Ok(match self.decode(buf)? {
Some(frame) => Some(frame),
None => {
// No terminating newline - return remaining data, if any
if buf.is_empty() || buf == &b"\r"[..] {
None
} else {
let line = buf.take();
let line = without_carriage_return(&line);
let line = utf8(line)?;
self.next_index = 0;
Some(line.to_string())
}
}
})
}
}
impl Encoder for LinesCodec {
type Item = String;
type Error = io::Error;
fn encode(&mut self, line: String, buf: &mut BytesMut) -> Result<(), io::Error> {
buf.reserve(line.len() + 1);
buf.put(line);
buf.put_u8(b'\n');
Ok(())
}
}
+202
View File
@@ -0,0 +1,202 @@
extern crate bytes;
extern crate tokio_codec;
use bytes::{BufMut, Bytes, BytesMut};
use tokio_codec::{BytesCodec, Decoder, Encoder, LinesCodec};
#[test]
fn bytes_decoder() {
let mut codec = BytesCodec::new();
let buf = &mut BytesMut::new();
buf.put_slice(b"abc");
assert_eq!("abc", codec.decode(buf).unwrap().unwrap());
assert_eq!(None, codec.decode(buf).unwrap());
assert_eq!(None, codec.decode(buf).unwrap());
buf.put_slice(b"a");
assert_eq!("a", codec.decode(buf).unwrap().unwrap());
}
#[test]
fn bytes_encoder() {
let mut codec = BytesCodec::new();
// Default capacity of BytesMut
#[cfg(target_pointer_width = "64")]
const INLINE_CAP: usize = 4 * 8 - 1;
#[cfg(target_pointer_width = "32")]
const INLINE_CAP: usize = 4 * 4 - 1;
let mut buf = BytesMut::new();
codec
.encode(Bytes::from_static(&[0; INLINE_CAP + 1]), &mut buf)
.unwrap();
// Default capacity of Framed Read
const INITIAL_CAPACITY: usize = 8 * 1024;
let mut buf = BytesMut::with_capacity(INITIAL_CAPACITY);
codec
.encode(Bytes::from_static(&[0; INITIAL_CAPACITY + 1]), &mut buf)
.unwrap();
}
#[test]
fn lines_decoder() {
let mut codec = LinesCodec::new();
let buf = &mut BytesMut::new();
buf.reserve(200);
buf.put("line 1\nline 2\r\nline 3\n\r\n\r");
assert_eq!("line 1", codec.decode(buf).unwrap().unwrap());
assert_eq!("line 2", codec.decode(buf).unwrap().unwrap());
assert_eq!("line 3", codec.decode(buf).unwrap().unwrap());
assert_eq!("", codec.decode(buf).unwrap().unwrap());
assert_eq!(None, codec.decode(buf).unwrap());
assert_eq!(None, codec.decode_eof(buf).unwrap());
buf.put("k");
assert_eq!(None, codec.decode(buf).unwrap());
assert_eq!("\rk", codec.decode_eof(buf).unwrap().unwrap());
assert_eq!(None, codec.decode(buf).unwrap());
assert_eq!(None, codec.decode_eof(buf).unwrap());
}
#[test]
fn lines_decoder_max_length() {
const MAX_LENGTH: usize = 6;
let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH);
let buf = &mut BytesMut::new();
buf.reserve(200);
buf.put("line 1 is too long\nline 2\nline 3\r\nline 4\n\r\n\r");
assert!(codec.decode(buf).is_err());
let line = codec.decode(buf).unwrap().unwrap();
assert!(
line.len() <= MAX_LENGTH,
"{:?}.len() <= {:?}",
line,
MAX_LENGTH
);
assert_eq!("line 2", line);
assert!(codec.decode(buf).is_err());
let line = codec.decode(buf).unwrap().unwrap();
assert!(
line.len() <= MAX_LENGTH,
"{:?}.len() <= {:?}",
line,
MAX_LENGTH
);
assert_eq!("line 4", line);
let line = codec.decode(buf).unwrap().unwrap();
assert!(
line.len() <= MAX_LENGTH,
"{:?}.len() <= {:?}",
line,
MAX_LENGTH
);
assert_eq!("", line);
assert_eq!(None, codec.decode(buf).unwrap());
assert_eq!(None, codec.decode_eof(buf).unwrap());
buf.put("k");
assert_eq!(None, codec.decode(buf).unwrap());
let line = codec.decode_eof(buf).unwrap().unwrap();
assert!(
line.len() <= MAX_LENGTH,
"{:?}.len() <= {:?}",
line,
MAX_LENGTH
);
assert_eq!("\rk", line);
assert_eq!(None, codec.decode(buf).unwrap());
assert_eq!(None, codec.decode_eof(buf).unwrap());
// Line that's one character too long. This could cause an out of bounds
// error if we peek at the next characters using slice indexing.
// buf.put("aaabbbc");
// assert!(codec.decode(buf).is_err());
}
#[test]
fn lines_decoder_max_length_underrun() {
const MAX_LENGTH: usize = 6;
let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH);
let buf = &mut BytesMut::new();
buf.reserve(200);
buf.put("line ");
assert_eq!(None, codec.decode(buf).unwrap());
buf.put("too l");
assert!(codec.decode(buf).is_err());
buf.put("ong\n");
assert_eq!(None, codec.decode(buf).unwrap());
buf.put("line 2");
assert_eq!(None, codec.decode(buf).unwrap());
buf.put("\n");
assert_eq!("line 2", codec.decode(buf).unwrap().unwrap());
}
#[test]
fn lines_decoder_max_length_bursts() {
const MAX_LENGTH: usize = 10;
let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH);
let buf = &mut BytesMut::new();
buf.reserve(200);
buf.put("line ");
assert_eq!(None, codec.decode(buf).unwrap());
buf.put("too l");
assert_eq!(None, codec.decode(buf).unwrap());
buf.put("ong\n");
assert!(codec.decode(buf).is_err());
}
#[test]
fn lines_decoder_max_length_big_burst() {
const MAX_LENGTH: usize = 10;
let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH);
let buf = &mut BytesMut::new();
buf.reserve(200);
buf.put("line ");
assert_eq!(None, codec.decode(buf).unwrap());
buf.put("too long!\n");
assert!(codec.decode(buf).is_err());
}
#[test]
fn lines_decoder_max_length_newline_between_decodes() {
const MAX_LENGTH: usize = 5;
let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH);
let buf = &mut BytesMut::new();
buf.reserve(200);
buf.put("hello");
assert_eq!(None, codec.decode(buf).unwrap());
buf.put("\nworld");
assert_eq!("hello", codec.decode(buf).unwrap().unwrap());
}
#[test]
fn lines_encoder() {
let mut codec = LinesCodec::new();
let mut buf = BytesMut::new();
codec.encode(String::from("line 1"), &mut buf).unwrap();
assert_eq!("line 1\n", buf);
codec.encode(String::from("line 2"), &mut buf).unwrap();
assert_eq!("line 1\nline 2\n", buf);
}
+94
View File
@@ -0,0 +1,94 @@
extern crate bytes;
extern crate futures;
extern crate tokio_codec;
extern crate tokio_io;
use bytes::{Buf, BufMut, BytesMut, IntoBuf};
use futures::{Future, Stream};
use std::io::{self, Read};
use tokio_codec::{Decoder, Encoder, Framed, FramedParts};
use tokio_io::AsyncRead;
const INITIAL_CAPACITY: usize = 8 * 1024;
/// Encode and decode u32 values.
struct U32Codec;
impl Decoder for U32Codec {
type Item = u32;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
if buf.len() < 4 {
return Ok(None);
}
let n = buf.split_to(4).into_buf().get_u32_be();
Ok(Some(n))
}
}
impl Encoder for U32Codec {
type Item = u32;
type Error = io::Error;
fn encode(&mut self, item: u32, dst: &mut BytesMut) -> io::Result<()> {
// Reserve space
dst.reserve(4);
dst.put_u32_be(item);
Ok(())
}
}
/// This value should never be used
struct DontReadIntoThis;
impl Read for DontReadIntoThis {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
Err(io::Error::new(
io::ErrorKind::Other,
"Read into something you weren't supposed to.",
))
}
}
impl AsyncRead for DontReadIntoThis {}
#[test]
fn can_read_from_existing_buf() {
let mut parts = FramedParts::new(DontReadIntoThis, U32Codec);
parts.read_buf = vec![0, 0, 0, 42].into();
let framed = Framed::from_parts(parts);
let num = framed
.into_future()
.map(|(first_num, _)| first_num.unwrap())
.wait()
.map_err(|e| e.0)
.unwrap();
assert_eq!(num, 42);
}
#[test]
fn external_buf_grows_to_init() {
let mut parts = FramedParts::new(DontReadIntoThis, U32Codec);
parts.read_buf = vec![0, 0, 0, 42].into();
let framed = Framed::from_parts(parts);
let FramedParts { read_buf, .. } = framed.into_parts();
assert_eq!(read_buf.capacity(), INITIAL_CAPACITY);
}
#[test]
fn external_buf_does_not_shrink() {
let mut parts = FramedParts::new(DontReadIntoThis, U32Codec);
parts.read_buf = vec![0; INITIAL_CAPACITY * 2].into();
let framed = Framed::from_parts(parts);
let FramedParts { read_buf, .. } = framed.into_parts();
assert_eq!(read_buf.capacity(), INITIAL_CAPACITY * 2);
}
+215
View File
@@ -0,0 +1,215 @@
extern crate bytes;
extern crate futures;
extern crate tokio_codec;
extern crate tokio_io;
use tokio_codec::{Decoder, FramedRead};
use tokio_io::AsyncRead;
use bytes::{Buf, BytesMut, IntoBuf};
use futures::Async::{NotReady, Ready};
use futures::Stream;
use std::collections::VecDeque;
use std::io::{self, Read};
macro_rules! mock {
($($x:expr,)*) => {{
let mut v = VecDeque::new();
v.extend(vec![$($x),*]);
Mock { calls: v }
}};
}
struct U32Decoder;
impl Decoder for U32Decoder {
type Item = u32;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
if buf.len() < 4 {
return Ok(None);
}
let n = buf.split_to(4).into_buf().get_u32_be();
Ok(Some(n))
}
}
#[test]
fn read_multi_frame_in_packet() {
let mock = mock! {
Ok(b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()),
};
let mut framed = FramedRead::new(mock, U32Decoder);
assert_eq!(Ready(Some(0)), framed.poll().unwrap());
assert_eq!(Ready(Some(1)), framed.poll().unwrap());
assert_eq!(Ready(Some(2)), framed.poll().unwrap());
assert_eq!(Ready(None), framed.poll().unwrap());
}
#[test]
fn read_multi_frame_across_packets() {
let mock = mock! {
Ok(b"\x00\x00\x00\x00".to_vec()),
Ok(b"\x00\x00\x00\x01".to_vec()),
Ok(b"\x00\x00\x00\x02".to_vec()),
};
let mut framed = FramedRead::new(mock, U32Decoder);
assert_eq!(Ready(Some(0)), framed.poll().unwrap());
assert_eq!(Ready(Some(1)), framed.poll().unwrap());
assert_eq!(Ready(Some(2)), framed.poll().unwrap());
assert_eq!(Ready(None), framed.poll().unwrap());
}
#[test]
fn read_not_ready() {
let mock = mock! {
Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
Ok(b"\x00\x00\x00\x00".to_vec()),
Ok(b"\x00\x00\x00\x01".to_vec()),
};
let mut framed = FramedRead::new(mock, U32Decoder);
assert_eq!(NotReady, framed.poll().unwrap());
assert_eq!(Ready(Some(0)), framed.poll().unwrap());
assert_eq!(Ready(Some(1)), framed.poll().unwrap());
assert_eq!(Ready(None), framed.poll().unwrap());
}
#[test]
fn read_partial_then_not_ready() {
let mock = mock! {
Ok(b"\x00\x00".to_vec()),
Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
Ok(b"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()),
};
let mut framed = FramedRead::new(mock, U32Decoder);
assert_eq!(NotReady, framed.poll().unwrap());
assert_eq!(Ready(Some(0)), framed.poll().unwrap());
assert_eq!(Ready(Some(1)), framed.poll().unwrap());
assert_eq!(Ready(Some(2)), framed.poll().unwrap());
assert_eq!(Ready(None), framed.poll().unwrap());
}
#[test]
fn read_err() {
let mock = mock! {
Err(io::Error::new(io::ErrorKind::Other, "")),
};
let mut framed = FramedRead::new(mock, U32Decoder);
assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind());
}
#[test]
fn read_partial_then_err() {
let mock = mock! {
Ok(b"\x00\x00".to_vec()),
Err(io::Error::new(io::ErrorKind::Other, "")),
};
let mut framed = FramedRead::new(mock, U32Decoder);
assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind());
}
#[test]
fn read_partial_would_block_then_err() {
let mock = mock! {
Ok(b"\x00\x00".to_vec()),
Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
Err(io::Error::new(io::ErrorKind::Other, "")),
};
let mut framed = FramedRead::new(mock, U32Decoder);
assert_eq!(NotReady, framed.poll().unwrap());
assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind());
}
#[test]
fn huge_size() {
let data = [0; 32 * 1024];
let mut framed = FramedRead::new(&data[..], BigDecoder);
assert_eq!(Ready(Some(0)), framed.poll().unwrap());
assert_eq!(Ready(None), framed.poll().unwrap());
struct BigDecoder;
impl Decoder for BigDecoder {
type Item = u32;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
if buf.len() < 32 * 1024 {
return Ok(None);
}
buf.split_to(32 * 1024);
Ok(Some(0))
}
}
}
#[test]
fn data_remaining_is_error() {
let data = [0; 5];
let mut framed = FramedRead::new(&data[..], U32Decoder);
assert_eq!(Ready(Some(0)), framed.poll().unwrap());
assert!(framed.poll().is_err());
}
#[test]
fn multi_frames_on_eof() {
struct MyDecoder(Vec<u32>);
impl Decoder for MyDecoder {
type Item = u32;
type Error = io::Error;
fn decode(&mut self, _buf: &mut BytesMut) -> io::Result<Option<u32>> {
unreachable!();
}
fn decode_eof(&mut self, _buf: &mut BytesMut) -> io::Result<Option<u32>> {
if self.0.is_empty() {
return Ok(None);
}
Ok(Some(self.0.remove(0)))
}
}
let mut framed = FramedRead::new(mock!(), MyDecoder(vec![0, 1, 2, 3]));
assert_eq!(Ready(Some(0)), framed.poll().unwrap());
assert_eq!(Ready(Some(1)), framed.poll().unwrap());
assert_eq!(Ready(Some(2)), framed.poll().unwrap());
assert_eq!(Ready(Some(3)), framed.poll().unwrap());
assert_eq!(Ready(None), framed.poll().unwrap());
}
// ===== Mock ======
struct Mock {
calls: VecDeque<io::Result<Vec<u8>>>,
}
impl Read for Mock {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
match self.calls.pop_front() {
Some(Ok(data)) => {
debug_assert!(dst.len() >= data.len());
dst[..data.len()].copy_from_slice(&data[..]);
Ok(data.len())
}
Some(Err(e)) => Err(e),
None => Ok(0),
}
}
}
impl AsyncRead for Mock {}
+134
View File
@@ -0,0 +1,134 @@
extern crate bytes;
extern crate futures;
extern crate tokio_codec;
extern crate tokio_io;
use tokio_codec::{Encoder, FramedWrite};
use tokio_io::AsyncWrite;
use bytes::{BufMut, BytesMut};
use futures::{Poll, Sink};
use std::collections::VecDeque;
use std::io::{self, Write};
macro_rules! mock {
($($x:expr,)*) => {{
let mut v = VecDeque::new();
v.extend(vec![$($x),*]);
Mock { calls: v }
}};
}
struct U32Encoder;
impl Encoder for U32Encoder {
type Item = u32;
type Error = io::Error;
fn encode(&mut self, item: u32, dst: &mut BytesMut) -> io::Result<()> {
// Reserve space
dst.reserve(4);
dst.put_u32_be(item);
Ok(())
}
}
#[test]
fn write_multi_frame_in_packet() {
let mock = mock! {
Ok(b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()),
};
let mut framed = FramedWrite::new(mock, U32Encoder);
assert!(framed.start_send(0).unwrap().is_ready());
assert!(framed.start_send(1).unwrap().is_ready());
assert!(framed.start_send(2).unwrap().is_ready());
// Nothing written yet
assert_eq!(1, framed.get_ref().calls.len());
// Flush the writes
assert!(framed.poll_complete().unwrap().is_ready());
assert_eq!(0, framed.get_ref().calls.len());
}
#[test]
fn write_hits_backpressure() {
const ITER: usize = 2 * 1024;
let mut mock = mock! {
// Block the `ITER`th write
Err(io::Error::new(io::ErrorKind::WouldBlock, "not ready")),
Ok(b"".to_vec()),
};
for i in 0..(ITER + 1) {
let mut b = BytesMut::with_capacity(4);
b.put_u32_be(i as u32);
// Append to the end
match mock.calls.back_mut().unwrap() {
&mut Ok(ref mut data) => {
// Write in 2kb chunks
if data.len() < ITER {
data.extend_from_slice(&b[..]);
continue;
}
}
_ => unreachable!(),
}
// Push a new new chunk
mock.calls.push_back(Ok(b[..].to_vec()));
}
let mut framed = FramedWrite::new(mock, U32Encoder);
for i in 0..ITER {
assert!(framed.start_send(i as u32).unwrap().is_ready());
}
// This should reject
assert!(!framed.start_send(ITER as u32).unwrap().is_ready());
// This should succeed and start flushing the buffer.
assert!(framed.start_send(ITER as u32).unwrap().is_ready());
// Flush the rest of the buffer
assert!(framed.poll_complete().unwrap().is_ready());
// Ensure the mock is empty
assert_eq!(0, framed.get_ref().calls.len());
}
// ===== Mock ======
struct Mock {
calls: VecDeque<io::Result<Vec<u8>>>,
}
impl Write for Mock {
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
match self.calls.pop_front() {
Some(Ok(data)) => {
assert!(src.len() >= data.len());
assert_eq!(&data[..], &src[..data.len()]);
Ok(data.len())
}
Some(Err(e)) => Err(e),
None => panic!("unexpected write; {:?}", src),
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl AsyncWrite for Mock {
fn shutdown(&mut self) -> Poll<(), io::Error> {
Ok(().into())
}
}
+35
View File
@@ -0,0 +1,35 @@
# 0.1.7 (February 4, 2020)
* Add `tokio 0.2.x` deprecation notice.
# 0.1.6 (March 22, 2019)
### Added
- implement `TypedExecutor` (#993).
# 0.1.5 (March 1, 2019)
### Fixed
- Documentation typos (#882).
# 0.1.4 (November 21, 2018)
* Fix shutdown on idle (#763).
# 0.1.3 (September 27, 2018)
* Fix minimal versions
# 0.1.2 (September 26, 2018)
* Implement `futures::Executor` for executor types (#563)
* Spawning performance improvements (#565)
# 0.1.1 (August 6, 2018)
* Implement `std::Error` for misc error types (#501)
* bugfix: Track tasks pending in spawn queue (#478)
# 0.1.0 (June 13, 2018)
* Extract `tokio::executor::current_thread` to a tokio-current-thread crate (#356)
+25
View File
@@ -0,0 +1,25 @@
[package]
name = "tokio-current-thread"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.7"
documentation = "https://docs.rs/tokio-current-thread/0.1.7/tokio_current_thread"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://github.com/tokio-rs/tokio"
license = "MIT"
authors = ["Carl Lerche <[email protected]>"]
description = """
Single threaded executor which manage many tasks concurrently on the current thread.
"""
keywords = ["futures", "tokio"]
categories = ["concurrency", "asynchronous"]
[dependencies]
tokio-executor = "0.1.7"
futures = "0.1.19"
+25
View File
@@ -0,0 +1,25 @@
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.
+28
View File
@@ -0,0 +1,28 @@
# tokio-current-thread
Single threaded executor for Tokio.
> **Note:** This crate is **deprecated in tokio 0.2.x** and has been moved and
> refactored into various places in the [`tokio`] crate. The closest replacement
> is to make use of [`tokio::task::LocalSet::block_on`] which requires the
> [`rt-util` feature].
[`tokio`]: https://docs.rs/tokio/latest/tokio/index.html
[`tokio::task::LocalSet::block_on`]: https://docs.rs/tokio/latest/tokio/task/struct.LocalSet.html#method.block_on
[`rt-util` feature]: https://docs.rs/tokio/latest/tokio/index.html#feature-flags
[Documentation](https://docs.rs/tokio-current-thread/0.1.6/tokio_current_thread/)
## Overview
This crate provides the single threaded executor which execute many tasks concurrently.
## 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.
+882
View File
@@ -0,0 +1,882 @@
#![doc(html_root_url = "https://docs.rs/tokio-current-thread/0.1.7")]
#![deny(missing_docs, missing_debug_implementations)]
//! A single-threaded executor which executes tasks on the same thread from which
//! they are spawned.
//!
//! > **Note:** This crate is **deprecated in tokio 0.2.x** and has been moved
//! > and refactored into various places in the [`tokio`] crate. The closest
//! replacement is to make use of [`tokio::task::LocalSet::block_on`] which
//! requires the [`rt-util` feature].
//!
//! [`tokio`]: https://docs.rs/tokio/latest/tokio/index.html
//! [`tokio::task::LocalSet::block_on`]: https://docs.rs/tokio/latest/tokio/task/struct.LocalSet.html#method.block_on
//! [`rt-util` feature]: https://docs.rs/tokio/latest/tokio/index.html#feature-flags
//!
//! The crate provides:
//!
//! * [`CurrentThread`] is the main type of this crate. It executes tasks on the current thread.
//! The easiest way to start a new [`CurrentThread`] executor is to call
//! [`block_on_all`] with an initial task to seed the executor.
//! All tasks that are being managed by a [`CurrentThread`] executor are able to
//! spawn additional tasks by calling [`spawn`].
//!
//!
//! Application authors will not use this crate directly. Instead, they will use the
//! `tokio` crate. Library authors should only depend on `tokio-current-thread` if they
//! are building a custom task executor.
//!
//! For more details, see [executor module] documentation in the Tokio crate.
//!
//! [`CurrentThread`]: struct.CurrentThread.html
//! [`spawn`]: fn.spawn.html
//! [`block_on_all`]: fn.block_on_all.html
//! [executor module]: https://docs.rs/tokio/0.1/tokio/executor/index.html
extern crate futures;
extern crate tokio_executor;
mod scheduler;
use self::scheduler::Scheduler;
use tokio_executor::park::{Park, ParkThread, Unpark};
use tokio_executor::{Enter, SpawnError};
use futures::future::{ExecuteError, ExecuteErrorKind, Executor};
use futures::{executor, Async, Future};
use std::cell::Cell;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::sync::{atomic, mpsc, Arc};
use std::thread;
use std::time::{Duration, Instant};
/// Executes tasks on the current thread
pub struct CurrentThread<P: Park = ParkThread> {
/// Execute futures and receive unpark notifications.
scheduler: Scheduler<P::Unpark>,
/// Current number of futures being executed.
///
/// The LSB is used to indicate that the runtime is preparing to shut down.
/// Thus, to get the actual number of pending futures, `>>1`.
num_futures: Arc<atomic::AtomicUsize>,
/// Thread park handle
park: P,
/// Handle for spawning new futures from other threads
spawn_handle: Handle,
/// Receiver for futures spawned from other threads
spawn_receiver: mpsc::Receiver<Box<dyn Future<Item = (), Error = ()> + Send + 'static>>,
/// The thread-local ID assigned to this executor.
id: u64,
}
/// Executes futures on the current thread.
///
/// All futures executed using this executor will be executed on the current
/// thread. As such, `run` will wait for these futures to complete before
/// returning.
///
/// For more details, see the [module level](index.html) documentation.
#[derive(Debug, Clone)]
pub struct TaskExecutor {
// Prevent the handle from moving across threads.
_p: ::std::marker::PhantomData<Rc<()>>,
}
/// Returned by the `turn` function.
#[derive(Debug)]
pub struct Turn {
polled: bool,
}
impl Turn {
/// `true` if any futures were polled at all and `false` otherwise.
pub fn has_polled(&self) -> bool {
self.polled
}
}
/// A `CurrentThread` instance bound to a supplied execution context.
pub struct Entered<'a, P: Park + 'a> {
executor: &'a mut CurrentThread<P>,
enter: &'a mut Enter,
}
/// Error returned by the `run` function.
#[derive(Debug)]
pub struct RunError {
_p: (),
}
impl fmt::Display for RunError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.description())
}
}
impl Error for RunError {
fn description(&self) -> &str {
"Run error"
}
}
/// Error returned by the `run_timeout` function.
#[derive(Debug)]
pub struct RunTimeoutError {
timeout: bool,
}
impl fmt::Display for RunTimeoutError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.description())
}
}
impl Error for RunTimeoutError {
fn description(&self) -> &str {
if self.timeout {
"Run timeout error (timeout)"
} else {
"Run timeout error (not timeout)"
}
}
}
/// Error returned by the `turn` function.
#[derive(Debug)]
pub struct TurnError {
_p: (),
}
impl fmt::Display for TurnError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.description())
}
}
impl Error for TurnError {
fn description(&self) -> &str {
"Turn error"
}
}
/// Error returned by the `block_on` function.
#[derive(Debug)]
pub struct BlockError<T> {
inner: Option<T>,
}
impl<T> fmt::Display for BlockError<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Block error")
}
}
impl<T: fmt::Debug> Error for BlockError<T> {
fn description(&self) -> &str {
"Block error"
}
}
/// This is mostly split out to make the borrow checker happy.
struct Borrow<'a, U: 'a> {
id: u64,
scheduler: &'a mut Scheduler<U>,
num_futures: &'a atomic::AtomicUsize,
}
trait SpawnLocal {
fn spawn_local(
&mut self,
future: Box<dyn Future<Item = (), Error = ()>>,
already_counted: bool,
);
}
struct CurrentRunner {
spawn: Cell<Option<*mut dyn SpawnLocal>>,
id: Cell<Option<u64>>,
}
thread_local! {
/// Current thread's task runner. This is set in `TaskRunner::with`
static CURRENT: CurrentRunner = CurrentRunner {
spawn: Cell::new(None),
id: Cell::new(None),
}
}
thread_local! {
/// Unique ID to assign to each new executor launched on this thread.
///
/// The unique ID is used to determine if the currently running executor matches the one
/// referred to by a `Handle` so that direct task dispatch can be used.
static EXECUTOR_ID: Cell<u64> = Cell::new(0)
}
/// Run the executor bootstrapping the execution with the provided future.
///
/// This creates a new [`CurrentThread`] executor, spawns the provided future,
/// and blocks the current thread until the provided future and **all**
/// subsequently spawned futures complete. In other words:
///
/// * If the provided bootstrap future does **not** spawn any additional tasks,
/// `block_on_all` returns once `future` completes.
/// * If the provided bootstrap future **does** spawn additional tasks, then
/// `block_on_all` returns once **all** spawned futures complete.
///
/// See [module level][mod] documentation for more details.
///
/// [`CurrentThread`]: struct.CurrentThread.html
/// [mod]: index.html
pub fn block_on_all<F>(future: F) -> Result<F::Item, F::Error>
where
F: Future,
{
let mut current_thread = CurrentThread::new();
let ret = current_thread.block_on(future);
current_thread.run().unwrap();
ret.map_err(|e| e.into_inner().expect("unexpected execution error"))
}
/// Executes a future on the current thread.
///
/// The provided future must complete or be canceled before `run` will return.
///
/// Unlike [`tokio::spawn`], this function will always spawn on a
/// `CurrentThread` executor and is able to spawn futures that are not `Send`.
///
/// # Panics
///
/// This function can only be invoked from the context of a `run` call; any
/// other use will result in a panic.
///
/// [`tokio::spawn`]: ../fn.spawn.html
pub fn spawn<F>(future: F)
where
F: Future<Item = (), Error = ()> + 'static,
{
TaskExecutor::current()
.spawn_local(Box::new(future))
.unwrap();
}
// ===== impl CurrentThread =====
impl CurrentThread<ParkThread> {
/// Create a new instance of `CurrentThread`.
pub fn new() -> Self {
CurrentThread::new_with_park(ParkThread::new())
}
}
impl<P: Park> CurrentThread<P> {
/// Create a new instance of `CurrentThread` backed by the given park
/// handle.
pub fn new_with_park(park: P) -> Self {
let unpark = park.unpark();
let (spawn_sender, spawn_receiver) = mpsc::channel();
let thread = thread::current().id();
let id = EXECUTOR_ID.with(|idc| {
let id = idc.get();
idc.set(id + 1);
id
});
let scheduler = Scheduler::new(unpark);
let notify = scheduler.notify();
let num_futures = Arc::new(atomic::AtomicUsize::new(0));
CurrentThread {
scheduler: scheduler,
num_futures: num_futures.clone(),
park,
id,
spawn_handle: Handle {
sender: spawn_sender,
num_futures: num_futures,
notify: notify,
shut_down: Cell::new(false),
thread: thread,
id,
},
spawn_receiver: spawn_receiver,
}
}
/// Returns `true` if the executor is currently idle.
///
/// An idle executor is defined by not currently having any spawned tasks.
///
/// Note that this method is inherently racy -- if a future is spawned from a remote `Handle`,
/// this method may return `true` even though there are more futures to be executed.
pub fn is_idle(&self) -> bool {
self.num_futures.load(atomic::Ordering::SeqCst) <= 1
}
/// Spawn the future on the executor.
///
/// This internally queues the future to be executed once `run` is called.
pub fn spawn<F>(&mut self, future: F) -> &mut Self
where
F: Future<Item = (), Error = ()> + 'static,
{
self.borrow().spawn_local(Box::new(future), false);
self
}
/// Synchronously waits for the provided `future` to complete.
///
/// This function can be used to synchronously block the current thread
/// until the provided `future` has resolved either successfully or with an
/// error. The result of the future is then returned from this function
/// call.
///
/// Note that this function will **also** execute any spawned futures on the
/// current thread, but will **not** block until these other spawned futures
/// have completed.
///
/// The caller is responsible for ensuring that other spawned futures
/// complete execution.
pub fn block_on<F>(&mut self, future: F) -> Result<F::Item, BlockError<F::Error>>
where
F: Future,
{
let mut enter = tokio_executor::enter().expect("failed to start `current_thread::Runtime`");
self.enter(&mut enter).block_on(future)
}
/// Run the executor to completion, blocking the thread until **all**
/// spawned futures have completed.
pub fn run(&mut self) -> Result<(), RunError> {
let mut enter = tokio_executor::enter().expect("failed to start `current_thread::Runtime`");
self.enter(&mut enter).run()
}
/// Run the executor to completion, blocking the thread until all
/// spawned futures have completed **or** `duration` time has elapsed.
pub fn run_timeout(&mut self, duration: Duration) -> Result<(), RunTimeoutError> {
let mut enter = tokio_executor::enter().expect("failed to start `current_thread::Runtime`");
self.enter(&mut enter).run_timeout(duration)
}
/// Perform a single iteration of the event loop.
///
/// This function blocks the current thread even if the executor is idle.
pub fn turn(&mut self, duration: Option<Duration>) -> Result<Turn, TurnError> {
let mut enter = tokio_executor::enter().expect("failed to start `current_thread::Runtime`");
self.enter(&mut enter).turn(duration)
}
/// Bind `CurrentThread` instance with an execution context.
pub fn enter<'a>(&'a mut self, enter: &'a mut Enter) -> Entered<'a, P> {
Entered {
executor: self,
enter,
}
}
/// Returns a reference to the underlying `Park` instance.
pub fn get_park(&self) -> &P {
&self.park
}
/// Returns a mutable reference to the underlying `Park` instance.
pub fn get_park_mut(&mut self) -> &mut P {
&mut self.park
}
fn borrow(&mut self) -> Borrow<P::Unpark> {
Borrow {
id: self.id,
scheduler: &mut self.scheduler,
num_futures: &*self.num_futures,
}
}
/// Get a new handle to spawn futures on the executor
///
/// Different to the executor itself, the handle can be sent to different
/// threads and can be used to spawn futures on the executor.
pub fn handle(&self) -> Handle {
self.spawn_handle.clone()
}
}
impl<P: Park> Drop for CurrentThread<P> {
fn drop(&mut self) {
// Signal to Handles that no more futures can be spawned by setting LSB.
//
// NOTE: this isn't technically necessary since the send on the mpsc will fail once the
// receiver is dropped, but it's useful to illustrate how clean shutdown will be
// implemented (e.g., by setting the LSB).
let pending = self.num_futures.fetch_add(1, atomic::Ordering::SeqCst);
// TODO: We currently ignore any pending futures at the time we shut down.
//
// The "proper" fix for this is to have an explicit shutdown phase (`shutdown_on_idle`)
// which sets LSB (as above) do make Handle::spawn stop working, and then runs until
// num_futures.load() == 1.
let _ = pending;
}
}
impl tokio_executor::Executor for CurrentThread {
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
self.borrow().spawn_local(future, false);
Ok(())
}
}
impl<T> tokio_executor::TypedExecutor<T> for CurrentThread
where
T: Future<Item = (), Error = ()> + 'static,
{
fn spawn(&mut self, future: T) -> Result<(), SpawnError> {
self.borrow().spawn_local(Box::new(future), false);
Ok(())
}
}
impl<P: Park> fmt::Debug for CurrentThread<P> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("CurrentThread")
.field("scheduler", &self.scheduler)
.field(
"num_futures",
&self.num_futures.load(atomic::Ordering::SeqCst),
)
.finish()
}
}
// ===== impl Entered =====
impl<'a, P: Park> Entered<'a, P> {
/// Spawn the future on the executor.
///
/// This internally queues the future to be executed once `run` is called.
pub fn spawn<F>(&mut self, future: F) -> &mut Self
where
F: Future<Item = (), Error = ()> + 'static,
{
self.executor.borrow().spawn_local(Box::new(future), false);
self
}
/// Synchronously waits for the provided `future` to complete.
///
/// This function can be used to synchronously block the current thread
/// until the provided `future` has resolved either successfully or with an
/// error. The result of the future is then returned from this function
/// call.
///
/// Note that this function will **also** execute any spawned futures on the
/// current thread, but will **not** block until these other spawned futures
/// have completed.
///
/// The caller is responsible for ensuring that other spawned futures
/// complete execution.
pub fn block_on<F>(&mut self, future: F) -> Result<F::Item, BlockError<F::Error>>
where
F: Future,
{
let mut future = executor::spawn(future);
let notify = self.executor.scheduler.notify();
loop {
let res = self
.executor
.borrow()
.enter(self.enter, || future.poll_future_notify(&notify, 0));
match res {
Ok(Async::Ready(e)) => return Ok(e),
Err(e) => return Err(BlockError { inner: Some(e) }),
Ok(Async::NotReady) => {}
}
self.tick();
if let Err(_) = self.executor.park.park() {
return Err(BlockError { inner: None });
}
}
}
/// Run the executor to completion, blocking the thread until **all**
/// spawned futures have completed.
pub fn run(&mut self) -> Result<(), RunError> {
self.run_timeout2(None).map_err(|_| RunError { _p: () })
}
/// Run the executor to completion, blocking the thread until all
/// spawned futures have completed **or** `duration` time has elapsed.
pub fn run_timeout(&mut self, duration: Duration) -> Result<(), RunTimeoutError> {
self.run_timeout2(Some(duration))
}
/// Perform a single iteration of the event loop.
///
/// This function blocks the current thread even if the executor is idle.
pub fn turn(&mut self, duration: Option<Duration>) -> Result<Turn, TurnError> {
let res = if self.executor.scheduler.has_pending_futures() {
self.executor.park.park_timeout(Duration::from_millis(0))
} else {
match duration {
Some(duration) => self.executor.park.park_timeout(duration),
None => self.executor.park.park(),
}
};
if res.is_err() {
return Err(TurnError { _p: () });
}
let polled = self.tick();
Ok(Turn { polled })
}
/// Returns a reference to the underlying `Park` instance.
pub fn get_park(&self) -> &P {
&self.executor.park
}
/// Returns a mutable reference to the underlying `Park` instance.
pub fn get_park_mut(&mut self) -> &mut P {
&mut self.executor.park
}
fn run_timeout2(&mut self, dur: Option<Duration>) -> Result<(), RunTimeoutError> {
if self.executor.is_idle() {
// Nothing to do
return Ok(());
}
let mut time = dur.map(|dur| (Instant::now() + dur, dur));
loop {
self.tick();
if self.executor.is_idle() {
return Ok(());
}
match time {
Some((until, rem)) => {
if let Err(_) = self.executor.park.park_timeout(rem) {
return Err(RunTimeoutError::new(false));
}
let now = Instant::now();
if now >= until {
return Err(RunTimeoutError::new(true));
}
time = Some((until, until - now));
}
None => {
if let Err(_) = self.executor.park.park() {
return Err(RunTimeoutError::new(false));
}
}
}
}
}
/// Returns `true` if any futures were processed
fn tick(&mut self) -> bool {
// Spawn any futures that were spawned from other threads by manually
// looping over the receiver stream
// FIXME: Slightly ugly but needed to make the borrow checker happy
let (mut borrow, spawn_receiver) = (
Borrow {
id: self.executor.id,
scheduler: &mut self.executor.scheduler,
num_futures: &*self.executor.num_futures,
},
&mut self.executor.spawn_receiver,
);
while let Ok(future) = spawn_receiver.try_recv() {
borrow.spawn_local(future, true);
}
// After any pending futures were scheduled, do the actual tick
borrow
.scheduler
.tick(borrow.id, &mut *self.enter, borrow.num_futures)
}
}
impl<'a, P: Park> fmt::Debug for Entered<'a, P> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Entered")
.field("executor", &self.executor)
.field("enter", &self.enter)
.finish()
}
}
// ===== impl Handle =====
/// Handle to spawn a future on the corresponding `CurrentThread` instance
#[derive(Clone)]
pub struct Handle {
sender: mpsc::Sender<Box<dyn Future<Item = (), Error = ()> + Send + 'static>>,
num_futures: Arc<atomic::AtomicUsize>,
shut_down: Cell<bool>,
notify: executor::NotifyHandle,
thread: thread::ThreadId,
/// The thread-local ID assigned to this Handle's executor.
id: u64,
}
// Manual implementation because the Sender does not implement Debug
impl fmt::Debug for Handle {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Handle")
.field("shut_down", &self.shut_down.get())
.finish()
}
}
impl Handle {
/// Spawn a future onto the `CurrentThread` instance corresponding to this handle
///
/// # Panics
///
/// This function panics if the spawn fails. Failure occurs if the `CurrentThread`
/// instance of the `Handle` does not exist anymore.
pub fn spawn<F>(&self, future: F) -> Result<(), SpawnError>
where
F: Future<Item = (), Error = ()> + Send + 'static,
{
if thread::current().id() == self.thread {
let mut e = TaskExecutor::current();
if e.id() == Some(self.id) {
return e.spawn_local(Box::new(future));
}
}
if self.shut_down.get() {
return Err(SpawnError::shutdown());
}
// NOTE: += 2 since LSB is the shutdown bit
let pending = self.num_futures.fetch_add(2, atomic::Ordering::SeqCst);
if pending % 2 == 1 {
// Bring the count back so we still know when the Runtime is idle.
self.num_futures.fetch_sub(2, atomic::Ordering::SeqCst);
// Once the Runtime is shutting down, we know it won't come back.
self.shut_down.set(true);
return Err(SpawnError::shutdown());
}
self.sender
.send(Box::new(future))
.expect("CurrentThread does not exist anymore");
// use 0 for the id, CurrentThread does not make use of it
self.notify.notify(0);
Ok(())
}
/// Provides a best effort **hint** to whether or not `spawn` will succeed.
///
/// This function may return both false positives **and** false negatives.
/// If `status` returns `Ok`, then a call to `spawn` will *probably*
/// succeed, but may fail. If `status` returns `Err`, a call to `spawn` will
/// *probably* fail, but may succeed.
///
/// This allows a caller to avoid creating the task if the call to `spawn`
/// has a high likelihood of failing.
pub fn status(&self) -> Result<(), SpawnError> {
if self.shut_down.get() {
return Err(SpawnError::shutdown());
}
Ok(())
}
}
// ===== impl TaskExecutor =====
impl TaskExecutor {
/// Returns an executor that executes futures on the current thread.
///
/// The user of `TaskExecutor` must ensure that when a future is submitted,
/// that it is done within the context of a call to `run`.
///
/// For more details, see the [module level](index.html) documentation.
pub fn current() -> TaskExecutor {
TaskExecutor {
_p: ::std::marker::PhantomData,
}
}
/// Get the current executor's thread-local ID.
fn id(&self) -> Option<u64> {
CURRENT.with(|current| current.id.get())
}
/// Spawn a future onto the current `CurrentThread` instance.
pub fn spawn_local(
&mut self,
future: Box<dyn Future<Item = (), Error = ()>>,
) -> Result<(), SpawnError> {
CURRENT.with(|current| match current.spawn.get() {
Some(spawn) => {
unsafe { (*spawn).spawn_local(future, false) };
Ok(())
}
None => Err(SpawnError::shutdown()),
})
}
}
impl tokio_executor::Executor for TaskExecutor {
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
self.spawn_local(future)
}
}
impl<F> tokio_executor::TypedExecutor<F> for TaskExecutor
where
F: Future<Item = (), Error = ()> + 'static,
{
fn spawn(&mut self, future: F) -> Result<(), SpawnError> {
self.spawn_local(Box::new(future))
}
}
impl<F> Executor<F> for TaskExecutor
where
F: Future<Item = (), Error = ()> + 'static,
{
fn execute(&self, future: F) -> Result<(), ExecuteError<F>> {
CURRENT.with(|current| match current.spawn.get() {
Some(spawn) => {
unsafe { (*spawn).spawn_local(Box::new(future), false) };
Ok(())
}
None => Err(ExecuteError::new(ExecuteErrorKind::Shutdown, future)),
})
}
}
// ===== impl Borrow =====
impl<'a, U: Unpark> Borrow<'a, U> {
fn enter<F, R>(&mut self, _: &mut Enter, f: F) -> R
where
F: FnOnce() -> R,
{
CURRENT.with(|current| {
current.id.set(Some(self.id));
current.set_spawn(self, || f())
})
}
}
impl<'a, U: Unpark> SpawnLocal for Borrow<'a, U> {
fn spawn_local(
&mut self,
future: Box<dyn Future<Item = (), Error = ()>>,
already_counted: bool,
) {
if !already_counted {
// NOTE: we have a borrow of the Runtime, so we know that it isn't shut down.
// NOTE: += 2 since LSB is the shutdown bit
self.num_futures.fetch_add(2, atomic::Ordering::SeqCst);
}
self.scheduler.schedule(future);
}
}
// ===== impl CurrentRunner =====
impl CurrentRunner {
fn set_spawn<F, R>(&self, spawn: &mut dyn SpawnLocal, f: F) -> R
where
F: FnOnce() -> R,
{
struct Reset<'a>(&'a CurrentRunner);
impl<'a> Drop for Reset<'a> {
fn drop(&mut self) {
self.0.spawn.set(None);
self.0.id.set(None);
}
}
let _reset = Reset(self);
let spawn = unsafe { hide_lt(spawn as *mut dyn SpawnLocal) };
self.spawn.set(Some(spawn));
f()
}
}
unsafe fn hide_lt<'a>(p: *mut (dyn SpawnLocal + 'a)) -> *mut (dyn SpawnLocal + 'static) {
use std::mem;
mem::transmute(p)
}
// ===== impl RunTimeoutError =====
impl RunTimeoutError {
fn new(timeout: bool) -> Self {
RunTimeoutError { timeout }
}
/// Returns `true` if the error was caused by the operation timing out.
pub fn is_timeout(&self) -> bool {
self.timeout
}
}
impl From<tokio_executor::EnterError> for RunTimeoutError {
fn from(_: tokio_executor::EnterError) -> Self {
RunTimeoutError::new(false)
}
}
// ===== impl BlockError =====
impl<T> BlockError<T> {
/// Returns the error yielded by the future being blocked on
pub fn into_inner(self) -> Option<T> {
self.inner
}
}
impl<T> From<tokio_executor::EnterError> for BlockError<T> {
fn from(_: tokio_executor::EnterError) -> Self {
BlockError { inner: None }
}
}
+770
View File
@@ -0,0 +1,770 @@
use super::Borrow;
use tokio_executor::park::Unpark;
use tokio_executor::Enter;
use futures::executor::{self, NotifyHandle, Spawn, UnsafeNotify};
use futures::{Async, Future};
use std::cell::UnsafeCell;
use std::fmt::{self, Debug};
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release, SeqCst};
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize};
use std::sync::{Arc, Weak};
use std::thread;
use std::usize;
/// A generic task-aware scheduler.
///
/// This is used both by `FuturesUnordered` and the current-thread executor.
pub struct Scheduler<U> {
inner: Arc<Inner<U>>,
nodes: List<U>,
}
pub struct Notify<'a, U: 'a>(&'a Arc<Node<U>>);
// A linked-list of nodes
struct List<U> {
len: usize,
head: *const Node<U>,
tail: *const Node<U>,
}
// Scheduler is implemented using two linked lists. The first linked list tracks
// all items managed by a `Scheduler`. This list is stored on the `Scheduler`
// struct and is **not** thread safe. The second linked list is an
// implementation of the intrusive MPSC queue algorithm described by
// 1024cores.net and is stored on `Inner`. This linked list can push items to
// the back concurrently but only one consumer may pop from the front. To
// enforce this requirement, all popping will be performed via fns on
// `Scheduler` that take `&mut self`.
//
// When a item is submitted to the set a node is allocated and inserted in
// both linked lists. This means that all insertion operations **must** be
// originated from `Scheduler` with `&mut self` The next call to `tick` will
// (eventually) see this node and call `poll` on the item.
//
// Nodes are wrapped in `Arc` cells which manage the lifetime of the node.
// However, `Arc` handles are sometimes cast to `*const Node` pointers.
// Specifically, when a node is stored in at least one of the two lists
// described above, this represents a logical `Arc` handle. This is how
// `Scheduler` maintains its reference to all nodes it manages. Each
// `NotifyHandle` instance is an `Arc<Node>` as well.
//
// When `Scheduler` drops, it clears the linked list of all nodes that it
// manages. When doing so, it must attempt to decrement the reference count (by
// dropping an Arc handle). However, it can **only** decrement the reference
// count if the node is not currently stored in the mpsc channel. If the node
// **is** "queued" in the mpsc channel, then the arc reference count cannot be
// decremented. Once the node is popped from the mpsc channel, then the final
// arc reference count can be decremented, thus freeing the node.
struct Inner<U> {
// Thread unpark handle
unpark: U,
// Tick number
tick_num: AtomicUsize,
// Head/tail of the readiness queue
head_readiness: AtomicPtr<Node<U>>,
tail_readiness: UnsafeCell<*const Node<U>>,
// Used as part of the mpsc queue algorithm
stub: Arc<Node<U>>,
}
unsafe impl<U: Sync + Send> Send for Inner<U> {}
unsafe impl<U: Sync + Send> Sync for Inner<U> {}
impl<U: Unpark> executor::Notify for Inner<U> {
fn notify(&self, _: usize) {
self.unpark.unpark();
}
}
struct Node<U> {
// The item
item: UnsafeCell<Option<Task>>,
// The tick at which this node was notified
notified_at: AtomicUsize,
// Next pointer for linked list tracking all active nodes
next_all: UnsafeCell<*const Node<U>>,
// Previous node in linked list tracking all active nodes
prev_all: UnsafeCell<*const Node<U>>,
// Next pointer in readiness queue
next_readiness: AtomicPtr<Node<U>>,
// Whether or not this node is currently in the mpsc queue.
queued: AtomicBool,
// Queue that we'll be enqueued to when notified
queue: Weak<Inner<U>>,
}
/// Returned by `Inner::dequeue`, representing either a dequeue success (with
/// the dequeued node), an empty list, or an inconsistent state.
///
/// The inconsistent state is described in more detail at [1024cores], but
/// roughly indicates that a node will be ready to dequeue sometime shortly in
/// the future and the caller should try again soon.
///
/// [1024cores]: http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
enum Dequeue<U> {
Data(*const Node<U>),
Empty,
Yield,
Inconsistent,
}
/// Wraps a spawned boxed future
struct Task(Spawn<Box<dyn Future<Item = (), Error = ()>>>);
/// A task that is scheduled. `turn` must be called
pub struct Scheduled<'a, U: 'a> {
task: &'a mut Task,
notify: &'a Notify<'a, U>,
done: &'a mut bool,
}
impl<U> Scheduler<U>
where
U: Unpark,
{
/// Constructs a new, empty `Scheduler`
///
/// The returned `Scheduler` does not contain any items and, in this
/// state, `Scheduler::poll` will return `Ok(Async::Ready(None))`.
pub fn new(unpark: U) -> Self {
let stub = Arc::new(Node {
item: UnsafeCell::new(None),
notified_at: AtomicUsize::new(0),
next_all: UnsafeCell::new(ptr::null()),
prev_all: UnsafeCell::new(ptr::null()),
next_readiness: AtomicPtr::new(ptr::null_mut()),
queued: AtomicBool::new(true),
queue: Weak::new(),
});
let stub_ptr = &*stub as *const Node<U>;
let inner = Arc::new(Inner {
unpark,
tick_num: AtomicUsize::new(0),
head_readiness: AtomicPtr::new(stub_ptr as *mut _),
tail_readiness: UnsafeCell::new(stub_ptr),
stub: stub,
});
Scheduler {
inner: inner,
nodes: List::new(),
}
}
pub fn notify(&self) -> NotifyHandle {
self.inner.clone().into()
}
pub fn schedule(&mut self, item: Box<dyn Future<Item = (), Error = ()>>) {
// Get the current scheduler tick
let tick_num = self.inner.tick_num.load(SeqCst);
let node = Arc::new(Node {
item: UnsafeCell::new(Some(Task::new(item))),
notified_at: AtomicUsize::new(tick_num),
next_all: UnsafeCell::new(ptr::null_mut()),
prev_all: UnsafeCell::new(ptr::null_mut()),
next_readiness: AtomicPtr::new(ptr::null_mut()),
queued: AtomicBool::new(true),
queue: Arc::downgrade(&self.inner),
});
// Right now our node has a strong reference count of 1. We transfer
// ownership of this reference count to our internal linked list
// and we'll reclaim ownership through the `unlink` function below.
let ptr = self.nodes.push_back(node);
// We'll need to get the item "into the system" to start tracking it,
// e.g. getting its unpark notifications going to us tracking which
// items are ready. To do that we unconditionally enqueue it for
// polling here.
self.inner.enqueue(ptr);
}
/// Returns `true` if there are currently any pending futures
pub fn has_pending_futures(&mut self) -> bool {
// See function definition for why the unsafe is needed and
// correctly used here
unsafe { self.inner.has_pending_futures() }
}
/// Advance the scheduler state, returning `true` if any futures were
/// processed.
///
/// This function should be called whenever the caller is notified via a
/// wakeup.
pub fn tick(&mut self, eid: u64, enter: &mut Enter, num_futures: &AtomicUsize) -> bool {
let mut ret = false;
let tick = self.inner.tick_num.fetch_add(1, SeqCst).wrapping_add(1);
loop {
let node = match unsafe { self.inner.dequeue(Some(tick)) } {
Dequeue::Empty => {
return ret;
}
Dequeue::Yield => {
self.inner.unpark.unpark();
return ret;
}
Dequeue::Inconsistent => {
thread::yield_now();
continue;
}
Dequeue::Data(node) => node,
};
ret = true;
debug_assert!(node != self.inner.stub());
unsafe {
if (*(*node).item.get()).is_none() {
// The node has already been released. However, while it was
// being released, another thread notified it, which
// resulted in it getting pushed into the mpsc channel.
//
// In this case, we just decrement the ref count.
let node = ptr2arc(node);
assert!((*node.next_all.get()).is_null());
assert!((*node.prev_all.get()).is_null());
continue;
};
// We're going to need to be very careful if the `poll`
// function below panics. We need to (a) not leak memory and
// (b) ensure that we still don't have any use-after-frees. To
// manage this we do a few things:
//
// * This "bomb" here will call `release_node` if dropped
// abnormally. That way we'll be sure the memory management
// of the `node` is managed correctly.
//
// * We unlink the node from our internal queue to preemptively
// assume is is complete (will return Ready or panic), in
// which case we'll want to discard it regardless.
//
struct Bomb<'a, U: Unpark + 'a> {
borrow: &'a mut Borrow<'a, U>,
enter: &'a mut Enter,
node: Option<Arc<Node<U>>>,
}
impl<'a, U: Unpark> Drop for Bomb<'a, U> {
fn drop(&mut self) {
if let Some(node) = self.node.take() {
self.borrow.enter(self.enter, || release_node(node))
}
}
}
let node = self.nodes.remove(node);
let mut borrow = Borrow {
id: eid,
scheduler: self,
num_futures,
};
let mut bomb = Bomb {
node: Some(node),
enter: enter,
borrow: &mut borrow,
};
let mut done = false;
// Now that the bomb holds the node, create a new scope. This
// scope ensures that the borrow will go out of scope before we
// mutate the node pointer in `bomb` again
{
let node = bomb.node.as_ref().unwrap();
// Get a reference to the inner future. We already ensured
// that the item `is_some`.
let item = (*node.item.get()).as_mut().unwrap();
// Unset queued flag... this must be done before
// polling. This ensures that the item gets
// rescheduled if it is notified **during** a call
// to `poll`.
let prev = (*node).queued.swap(false, SeqCst);
assert!(prev);
// Poll the underlying item with the appropriate `notify`
// implementation. This is where a large bit of the unsafety
// starts to stem from internally. The `notify` instance itself
// is basically just our `Arc<Node>` and tracks the mpsc
// queue of ready items.
//
// Critically though `Node` won't actually access `Task`, the
// item, while it's floating around inside of `Task`
// instances. These structs will basically just use `T` to size
// the internal allocation, appropriately accessing fields and
// deallocating the node if need be.
let borrow = &mut *bomb.borrow;
let enter = &mut *bomb.enter;
let notify = Notify(bomb.node.as_ref().unwrap());
let mut scheduled = Scheduled {
task: item,
notify: &notify,
done: &mut done,
};
if borrow.enter(enter, || scheduled.tick()) {
// we have a borrow of the Runtime, so we know it's not shut down
borrow.num_futures.fetch_sub(2, SeqCst);
}
}
if !done {
// The future is not done, push it back into the "all
// node" list.
let node = bomb.node.take().unwrap();
bomb.borrow.scheduler.nodes.push_back(node);
}
}
}
}
}
impl<'a, U: Unpark> Scheduled<'a, U> {
/// Polls the task, returns `true` if the task has completed.
pub fn tick(&mut self) -> bool {
// Tick the future
let ret = match self.task.0.poll_future_notify(self.notify, 0) {
Ok(Async::Ready(_)) | Err(_) => true,
Ok(Async::NotReady) => false,
};
*self.done = ret;
ret
}
}
impl Task {
pub fn new(future: Box<dyn Future<Item = (), Error = ()> + 'static>) -> Self {
Task(executor::spawn(future))
}
}
impl fmt::Debug for Task {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Task").finish()
}
}
fn release_node<U>(node: Arc<Node<U>>) {
// The item is done, try to reset the queued flag. This will prevent
// `notify` from doing any work in the item
let prev = node.queued.swap(true, SeqCst);
// Drop the item, even if it hasn't finished yet. This is safe
// because we're dropping the item on the thread that owns
// `Scheduler`, which correctly tracks T's lifetimes and such.
unsafe {
drop((*node.item.get()).take());
}
// If the queued flag was previously set then it means that this node
// is still in our internal mpsc queue. We then transfer ownership
// of our reference count to the mpsc queue, and it'll come along and
// free it later, noticing that the item is `None`.
//
// If, however, the queued flag was *not* set then we're safe to
// release our reference count on the internal node. The queued flag
// was set above so all item `enqueue` operations will not actually
// enqueue the node, so our node will never see the mpsc queue again.
// The node itself will be deallocated once all reference counts have
// been dropped by the various owning tasks elsewhere.
if prev {
mem::forget(node);
}
}
impl<U> Debug for Scheduler<U> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Scheduler {{ ... }}")
}
}
impl<U> Drop for Scheduler<U> {
fn drop(&mut self) {
// When a `Scheduler` is dropped we want to drop all items associated
// with it. At the same time though there may be tons of `Task` handles
// flying around which contain `Node` references inside them. We'll
// let those naturally get deallocated when the `Task` itself goes out
// of scope or gets notified.
while let Some(node) = self.nodes.pop_front() {
release_node(node);
}
// Note that at this point we could still have a bunch of nodes in the
// mpsc queue. None of those nodes, however, have items associated
// with them so they're safe to destroy on any thread. At this point
// the `Scheduler` struct, the owner of the one strong reference
// to `Inner` will drop the strong reference. At that point
// whichever thread releases the strong refcount last (be it this
// thread or some other thread as part of an `upgrade`) will clear out
// the mpsc queue and free all remaining nodes.
//
// While that freeing operation isn't guaranteed to happen here, it's
// guaranteed to happen "promptly" as no more "blocking work" will
// happen while there's a strong refcount held.
}
}
impl<U> Inner<U> {
/// The enqueue function from the 1024cores intrusive MPSC queue algorithm.
fn enqueue(&self, node: *const Node<U>) {
unsafe {
debug_assert!((*node).queued.load(Relaxed));
// This action does not require any coordination
(*node).next_readiness.store(ptr::null_mut(), Relaxed);
// Note that these atomic orderings come from 1024cores
let node = node as *mut _;
let prev = self.head_readiness.swap(node, AcqRel);
(*prev).next_readiness.store(node, Release);
}
}
/// Returns `true` if there are currently any pending futures
///
/// See `dequeue` for an explanation why this function is unsafe.
unsafe fn has_pending_futures(&self) -> bool {
let tail = *self.tail_readiness.get();
let next = (*tail).next_readiness.load(Acquire);
if tail == self.stub() {
if next.is_null() {
return false;
}
}
true
}
/// The dequeue function from the 1024cores intrusive MPSC queue algorithm
///
/// Note that this unsafe as it required mutual exclusion (only one thread
/// can call this) to be guaranteed elsewhere.
unsafe fn dequeue(&self, tick: Option<usize>) -> Dequeue<U> {
let mut tail = *self.tail_readiness.get();
let mut next = (*tail).next_readiness.load(Acquire);
if tail == self.stub() {
if next.is_null() {
return Dequeue::Empty;
}
*self.tail_readiness.get() = next;
tail = next;
next = (*next).next_readiness.load(Acquire);
}
if let Some(tick) = tick {
let actual = (*tail).notified_at.load(SeqCst);
// Only dequeue if the node was not scheduled during the current
// tick.
if actual == tick {
// Only doing the check above **should** be enough in
// practice. However, technically there is a potential for
// deadlocking if there are `usize::MAX` ticks while the thread
// scheduling the task is frozen.
//
// If, for some reason, this is not enough, calling `unpark`
// here will resolve the issue.
return Dequeue::Yield;
}
}
if !next.is_null() {
*self.tail_readiness.get() = next;
debug_assert!(tail != self.stub());
return Dequeue::Data(tail);
}
if self.head_readiness.load(Acquire) as *const _ != tail {
return Dequeue::Inconsistent;
}
self.enqueue(self.stub());
next = (*tail).next_readiness.load(Acquire);
if !next.is_null() {
*self.tail_readiness.get() = next;
return Dequeue::Data(tail);
}
Dequeue::Inconsistent
}
fn stub(&self) -> *const Node<U> {
&*self.stub
}
}
impl<U> Drop for Inner<U> {
fn drop(&mut self) {
// Once we're in the destructor for `Inner` we need to clear out the
// mpsc queue of nodes if there's anything left in there.
//
// Note that each node has a strong reference count associated with it
// which is owned by the mpsc queue. All nodes should have had their
// items dropped already by the `Scheduler` destructor above,
// so we're just pulling out nodes and dropping their refcounts.
unsafe {
loop {
match self.dequeue(None) {
Dequeue::Empty => break,
Dequeue::Yield => unreachable!(),
Dequeue::Inconsistent => abort("inconsistent in drop"),
Dequeue::Data(ptr) => drop(ptr2arc(ptr)),
}
}
}
}
}
impl<U> List<U> {
fn new() -> Self {
List {
len: 0,
head: ptr::null_mut(),
tail: ptr::null_mut(),
}
}
/// Appends an element to the back of the list
fn push_back(&mut self, node: Arc<Node<U>>) -> *const Node<U> {
let ptr = arc2ptr(node);
unsafe {
// Point to the current last node in the list
*(*ptr).prev_all.get() = self.tail;
*(*ptr).next_all.get() = ptr::null_mut();
if !self.tail.is_null() {
*(*self.tail).next_all.get() = ptr;
self.tail = ptr;
} else {
// This is the first node
self.tail = ptr;
self.head = ptr;
}
}
self.len += 1;
return ptr;
}
/// Pop an element from the front of the list
fn pop_front(&mut self) -> Option<Arc<Node<U>>> {
if self.head.is_null() {
// The list is empty
return None;
}
self.len -= 1;
unsafe {
// Convert the ptr to Arc<_>
let node = ptr2arc(self.head);
// Update the head pointer
self.head = *node.next_all.get();
// If the pointer is null, then the list is empty
if self.head.is_null() {
self.tail = ptr::null_mut();
} else {
*(*self.head).prev_all.get() = ptr::null_mut();
}
Some(node)
}
}
/// Remove a specific node
unsafe fn remove(&mut self, node: *const Node<U>) -> Arc<Node<U>> {
let node = ptr2arc(node);
let next = *node.next_all.get();
let prev = *node.prev_all.get();
*node.next_all.get() = ptr::null_mut();
*node.prev_all.get() = ptr::null_mut();
if !next.is_null() {
*(*next).prev_all.get() = prev;
} else {
self.tail = prev;
}
if !prev.is_null() {
*(*prev).next_all.get() = next;
} else {
self.head = next;
}
self.len -= 1;
return node;
}
}
impl<'a, U> Clone for Notify<'a, U> {
fn clone(&self) -> Self {
Notify(self.0)
}
}
impl<'a, U> fmt::Debug for Notify<'a, U> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Notify").finish()
}
}
impl<'a, U: Unpark> From<Notify<'a, U>> for NotifyHandle {
fn from(handle: Notify<'a, U>) -> NotifyHandle {
unsafe {
let ptr = handle.0.clone();
let ptr = mem::transmute::<Arc<Node<U>>, *mut ArcNode<U>>(ptr);
NotifyHandle::new(hide_lt(ptr))
}
}
}
struct ArcNode<U>(PhantomData<U>);
// We should never touch `Task` on any thread other than the one owning
// `Scheduler`, so this should be a safe operation.
unsafe impl<U: Sync + Send> Send for ArcNode<U> {}
unsafe impl<U: Sync + Send> Sync for ArcNode<U> {}
impl<U: Unpark> executor::Notify for ArcNode<U> {
fn notify(&self, _id: usize) {
unsafe {
let me: *const ArcNode<U> = self;
let me: *const *const ArcNode<U> = &me;
let me = me as *const Arc<Node<U>>;
Node::notify(&*me)
}
}
}
unsafe impl<U: Unpark> UnsafeNotify for ArcNode<U> {
unsafe fn clone_raw(&self) -> NotifyHandle {
let me: *const ArcNode<U> = self;
let me: *const *const ArcNode<U> = &me;
let me = &*(me as *const Arc<Node<U>>);
Notify(me).into()
}
unsafe fn drop_raw(&self) {
let mut me: *const ArcNode<U> = self;
let me = &mut me as *mut *const ArcNode<U> as *mut Arc<Node<U>>;
ptr::drop_in_place(me);
}
}
unsafe fn hide_lt<U: Unpark>(p: *mut ArcNode<U>) -> *mut dyn UnsafeNotify {
mem::transmute(p as *mut dyn UnsafeNotify)
}
impl<U: Unpark> Node<U> {
fn notify(me: &Arc<Node<U>>) {
let inner = match me.queue.upgrade() {
Some(inner) => inner,
None => return,
};
// It's our job to notify the node that it's ready to get polled,
// meaning that we need to enqueue it into the readiness queue. To
// do this we flag that we're ready to be queued, and if successful
// we then do the literal queueing operation, ensuring that we're
// only queued once.
//
// Once the node is inserted we be sure to notify the parent task,
// as it'll want to come along and pick up our node now.
//
// Note that we don't change the reference count of the node here,
// we're just enqueueing the raw pointer. The `Scheduler`
// implementation guarantees that if we set the `queued` flag true that
// there's a reference count held by the main `Scheduler` queue
// still.
let prev = me.queued.swap(true, SeqCst);
if !prev {
// Get the current scheduler tick
let tick_num = inner.tick_num.load(SeqCst);
me.notified_at.store(tick_num, SeqCst);
inner.enqueue(&**me);
inner.unpark.unpark();
}
}
}
impl<U> Drop for Node<U> {
fn drop(&mut self) {
// Currently a `Node` is sent across all threads for any lifetime,
// regardless of `T`. This means that for memory safety we can't
// actually touch `T` at any time except when we have a reference to the
// `Scheduler` itself.
//
// Consequently it *should* be the case that we always drop items from
// the `Scheduler` instance, but this is a bomb in place to catch
// any bugs in that logic.
unsafe {
if (*self.item.get()).is_some() {
abort("item still here when dropping");
}
}
}
}
fn arc2ptr<T>(ptr: Arc<T>) -> *const T {
let addr = &*ptr as *const T;
mem::forget(ptr);
return addr;
}
unsafe fn ptr2arc<T>(ptr: *const T) -> Arc<T> {
let anchor = mem::transmute::<usize, Arc<T>>(0x10);
let addr = &*anchor as *const T;
mem::forget(anchor);
let offset = addr as isize - 0x10;
mem::transmute::<isize, Arc<T>>(ptr as isize - offset)
}
fn abort(s: &str) -> ! {
struct DoublePanic;
impl Drop for DoublePanic {
fn drop(&mut self) {
panic!("panicking twice to abort the program");
}
}
let _bomb = DoublePanic;
panic!("{}", s);
}
@@ -0,0 +1,835 @@
extern crate futures;
extern crate tokio_current_thread;
extern crate tokio_executor;
use tokio_current_thread::{block_on_all, CurrentThread};
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::thread;
use std::time::Duration;
use futures::future::{self, lazy};
use futures::task;
// This is not actually unused --- we need this trait to be in scope for
// the tests that sue TaskExecutor::current().execute(). The compiler
// doesn't realise that.
#[allow(unused_imports)]
use futures::future::Executor as _futures_Executor;
use futures::prelude::*;
use futures::sync::oneshot;
mod from_block_on_all {
use super::*;
fn test<F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static>(spawn: F) {
let cnt = Rc::new(Cell::new(0));
let c = cnt.clone();
let msg = tokio_current_thread::block_on_all(lazy(move || {
c.set(1 + c.get());
// Spawn!
spawn(Box::new(lazy(move || {
c.set(1 + c.get());
Ok::<(), ()>(())
})));
Ok::<_, ()>("hello")
}))
.unwrap();
assert_eq!(2, cnt.get());
assert_eq!(msg, "hello");
}
#[test]
fn spawn() {
test(tokio_current_thread::spawn)
}
#[test]
fn execute() {
test(|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.unwrap();
});
}
}
#[test]
fn block_waits() {
let (tx, rx) = oneshot::channel();
thread::spawn(|| {
thread::sleep(Duration::from_millis(1000));
tx.send(()).unwrap();
});
let cnt = Rc::new(Cell::new(0));
let cnt2 = cnt.clone();
block_on_all(rx.then(move |_| {
cnt.set(1 + cnt.get());
Ok::<_, ()>(())
}))
.unwrap();
assert_eq!(1, cnt2.get());
}
#[test]
fn spawn_many() {
const ITER: usize = 200;
let cnt = Rc::new(Cell::new(0));
let mut tokio_current_thread = CurrentThread::new();
for _ in 0..ITER {
let cnt = cnt.clone();
tokio_current_thread.spawn(lazy(move || {
cnt.set(1 + cnt.get());
Ok::<(), ()>(())
}));
}
tokio_current_thread.run().unwrap();
assert_eq!(cnt.get(), ITER);
}
mod does_not_set_global_executor_by_default {
use super::*;
fn test<F: Fn(Box<dyn Future<Item = (), Error = ()> + Send>) -> Result<(), E> + 'static, E>(
spawn: F,
) {
block_on_all(lazy(|| {
spawn(Box::new(lazy(|| ok()))).unwrap_err();
ok()
}))
.unwrap()
}
#[test]
fn spawn() {
use tokio_executor::Executor;
test(|f| tokio_executor::DefaultExecutor::current().spawn(f))
}
#[test]
fn execute() {
test(|f| tokio_executor::DefaultExecutor::current().execute(f))
}
}
mod from_block_on_future {
use super::*;
fn test<F: Fn(Box<dyn Future<Item = (), Error = ()>>)>(spawn: F) {
let cnt = Rc::new(Cell::new(0));
let mut tokio_current_thread = CurrentThread::new();
tokio_current_thread
.block_on(lazy(|| {
let cnt = cnt.clone();
spawn(Box::new(lazy(move || {
cnt.set(1 + cnt.get());
Ok(())
})));
Ok::<_, ()>(())
}))
.unwrap();
tokio_current_thread.run().unwrap();
assert_eq!(1, cnt.get());
}
#[test]
fn spawn() {
test(tokio_current_thread::spawn);
}
#[test]
fn execute() {
test(|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.unwrap();
});
}
}
struct Never(Rc<()>);
impl Future for Never {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
Ok(Async::NotReady)
}
}
mod outstanding_tasks_are_dropped_when_executor_is_dropped {
use super::*;
fn test<F, G>(spawn: F, dotspawn: G)
where
F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<dyn Future<Item = (), Error = ()>>),
{
let mut rc = Rc::new(());
let mut tokio_current_thread = CurrentThread::new();
dotspawn(&mut tokio_current_thread, Box::new(Never(rc.clone())));
drop(tokio_current_thread);
// Ensure the daemon is dropped
assert!(Rc::get_mut(&mut rc).is_some());
// Using the global spawn fn
let mut rc = Rc::new(());
let mut tokio_current_thread = CurrentThread::new();
tokio_current_thread
.block_on(lazy(|| {
spawn(Box::new(Never(rc.clone())));
Ok::<_, ()>(())
}))
.unwrap();
drop(tokio_current_thread);
// Ensure the daemon is dropped
assert!(Rc::get_mut(&mut rc).is_some());
}
#[test]
fn spawn() {
test(tokio_current_thread::spawn, |rt, f| {
rt.spawn(f);
})
}
#[test]
fn execute() {
test(
|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.unwrap();
},
// Note: `CurrentThread` doesn't currently implement
// `futures::Executor`, so we'll call `.spawn(...)` rather than
// `.execute(...)` for now. If `CurrentThread` is changed to
// implement Executor, change this to `.execute(...).unwrap()`.
|rt, f| {
rt.spawn(f);
},
);
}
}
#[test]
#[should_panic]
fn nesting_run() {
block_on_all(lazy(|| {
block_on_all(lazy(|| ok())).unwrap();
ok()
}))
.unwrap();
}
mod run_in_future {
use super::*;
#[test]
#[should_panic]
fn spawn() {
block_on_all(lazy(|| {
tokio_current_thread::spawn(lazy(|| {
block_on_all(lazy(|| ok())).unwrap();
ok()
}));
ok()
}))
.unwrap();
}
#[test]
#[should_panic]
fn execute() {
block_on_all(lazy(|| {
tokio_current_thread::TaskExecutor::current()
.execute(lazy(|| {
block_on_all(lazy(|| ok())).unwrap();
ok()
}))
.unwrap();
ok()
}))
.unwrap();
}
}
#[test]
fn tick_on_infini_future() {
let num = Rc::new(Cell::new(0));
struct Infini {
num: Rc<Cell<usize>>,
}
impl Future for Infini {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
self.num.set(1 + self.num.get());
task::current().notify();
Ok(Async::NotReady)
}
}
CurrentThread::new()
.spawn(Infini { num: num.clone() })
.turn(None)
.unwrap();
assert_eq!(1, num.get());
}
mod tasks_are_scheduled_fairly {
use super::*;
struct Spin {
state: Rc<RefCell<[i32; 2]>>,
idx: usize,
}
impl Future for Spin {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
let mut state = self.state.borrow_mut();
if self.idx == 0 {
let diff = state[0] - state[1];
assert!(diff.abs() <= 1);
if state[0] >= 50 {
return Ok(().into());
}
}
state[self.idx] += 1;
if state[self.idx] >= 100 {
return Ok(().into());
}
task::current().notify();
Ok(Async::NotReady)
}
}
fn test<F: Fn(Spin)>(spawn: F) {
let state = Rc::new(RefCell::new([0, 0]));
block_on_all(lazy(|| {
spawn(Spin {
state: state.clone(),
idx: 0,
});
spawn(Spin {
state: state,
idx: 1,
});
ok()
}))
.unwrap();
}
#[test]
fn spawn() {
test(tokio_current_thread::spawn)
}
#[test]
fn execute() {
test(|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.unwrap();
})
}
}
mod and_turn {
use super::*;
fn test<F, G>(spawn: F, dotspawn: G)
where
F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<dyn Future<Item = (), Error = ()>>),
{
let cnt = Rc::new(Cell::new(0));
let c = cnt.clone();
let mut tokio_current_thread = CurrentThread::new();
// Spawn a basic task to get the executor to turn
dotspawn(&mut tokio_current_thread, Box::new(lazy(move || Ok(()))));
// Turn once...
tokio_current_thread.turn(None).unwrap();
dotspawn(
&mut tokio_current_thread,
Box::new(lazy(move || {
c.set(1 + c.get());
// Spawn!
spawn(Box::new(lazy(move || {
c.set(1 + c.get());
Ok::<(), ()>(())
})));
Ok(())
})),
);
// This does not run the newly spawned thread
tokio_current_thread.turn(None).unwrap();
assert_eq!(1, cnt.get());
// This runs the newly spawned thread
tokio_current_thread.turn(None).unwrap();
assert_eq!(2, cnt.get());
}
#[test]
fn spawn() {
test(tokio_current_thread::spawn, |rt, f| {
rt.spawn(f);
})
}
#[test]
fn execute() {
test(
|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.unwrap();
},
// Note: `CurrentThread` doesn't currently implement
// `futures::Executor`, so we'll call `.spawn(...)` rather than
// `.execute(...)` for now. If `CurrentThread` is changed to
// implement Executor, change this to `.execute(...).unwrap()`.
|rt, f| {
rt.spawn(f);
},
);
}
}
mod in_drop {
use super::*;
struct OnDrop<F: FnOnce()>(Option<F>);
impl<F: FnOnce()> Drop for OnDrop<F> {
fn drop(&mut self) {
(self.0.take().unwrap())();
}
}
struct MyFuture {
_data: Box<dyn Any>,
}
impl Future for MyFuture {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
Ok(().into())
}
}
fn test<F, G>(spawn: F, dotspawn: G)
where
F: Fn(Box<dyn Future<Item = (), Error = ()>>) + 'static,
G: Fn(&mut CurrentThread, Box<dyn Future<Item = (), Error = ()>>),
{
let mut tokio_current_thread = CurrentThread::new();
let (tx, rx) = oneshot::channel();
dotspawn(
&mut tokio_current_thread,
Box::new(MyFuture {
_data: Box::new(OnDrop(Some(move || {
spawn(Box::new(lazy(move || {
tx.send(()).unwrap();
Ok(())
})));
}))),
}),
);
tokio_current_thread.block_on(rx).unwrap();
tokio_current_thread.run().unwrap();
}
#[test]
fn spawn() {
test(tokio_current_thread::spawn, |rt, f| {
rt.spawn(f);
})
}
#[test]
fn execute() {
test(
|f| {
tokio_current_thread::TaskExecutor::current()
.execute(f)
.unwrap();
},
// Note: `CurrentThread` doesn't currently implement
// `futures::Executor`, so we'll call `.spawn(...)` rather than
// `.execute(...)` for now. If `CurrentThread` is changed to
// implement Executor, change this to `.execute(...).unwrap()`.
|rt, f| {
rt.spawn(f);
},
);
}
}
#[test]
fn hammer_turn() {
use futures::sync::mpsc;
const ITER: usize = 100;
const N: usize = 100;
const THREADS: usize = 4;
for _ in 0..ITER {
let mut ths = vec![];
// Add some jitter
for _ in 0..THREADS {
let th = thread::spawn(|| {
let mut tokio_current_thread = CurrentThread::new();
let (tx, rx) = mpsc::unbounded();
tokio_current_thread.spawn({
let cnt = Rc::new(Cell::new(0));
let c = cnt.clone();
rx.for_each(move |_| {
c.set(1 + c.get());
Ok(())
})
.map_err(|e| panic!("err={:?}", e))
.map(move |v| {
assert_eq!(N, cnt.get());
v
})
});
thread::spawn(move || {
for _ in 0..N {
tx.unbounded_send(()).unwrap();
thread::yield_now();
}
});
while !tokio_current_thread.is_idle() {
tokio_current_thread.turn(None).unwrap();
}
});
ths.push(th);
}
for th in ths {
th.join().unwrap();
}
}
}
#[test]
fn turn_has_polled() {
let mut tokio_current_thread = CurrentThread::new();
// Spawn oneshot receiver
let (sender, receiver) = oneshot::channel::<()>();
tokio_current_thread.spawn(receiver.then(|_| Ok(())));
// Turn once...
let res = tokio_current_thread
.turn(Some(Duration::from_millis(0)))
.unwrap();
// Should've polled the receiver once, but considered it not ready
assert!(res.has_polled());
// Turn another time
let res = tokio_current_thread
.turn(Some(Duration::from_millis(0)))
.unwrap();
// Should've polled nothing, the receiver is not ready yet
assert!(!res.has_polled());
// Make the receiver ready
sender.send(()).unwrap();
// Turn another time
let res = tokio_current_thread
.turn(Some(Duration::from_millis(0)))
.unwrap();
// Should've polled the receiver, it's ready now
assert!(res.has_polled());
// Now the executor should be empty
assert!(tokio_current_thread.is_idle());
let res = tokio_current_thread
.turn(Some(Duration::from_millis(0)))
.unwrap();
// So should've polled nothing
assert!(!res.has_polled());
}
// Our own mock Park that is never really waiting and the only
// thing it does is to send, on request, something (once) to a oneshot
// channel
struct MyPark {
sender: Option<oneshot::Sender<()>>,
send_now: Rc<Cell<bool>>,
}
struct MyUnpark;
impl tokio_executor::park::Park for MyPark {
type Unpark = MyUnpark;
type Error = ();
fn unpark(&self) -> Self::Unpark {
MyUnpark
}
fn park(&mut self) -> Result<(), Self::Error> {
// If called twice with send_now, this will intentionally panic
if self.send_now.get() {
self.sender.take().unwrap().send(()).unwrap();
}
Ok(())
}
fn park_timeout(&mut self, _duration: Duration) -> Result<(), Self::Error> {
self.park()
}
}
impl tokio_executor::park::Unpark for MyUnpark {
fn unpark(&self) {}
}
#[test]
fn turn_fair() {
let send_now = Rc::new(Cell::new(false));
let (sender, receiver) = oneshot::channel::<()>();
let (sender_2, receiver_2) = oneshot::channel::<()>();
let (sender_3, receiver_3) = oneshot::channel::<()>();
let my_park = MyPark {
sender: Some(sender_3),
send_now: send_now.clone(),
};
let mut tokio_current_thread = CurrentThread::new_with_park(my_park);
let receiver_1_done = Rc::new(Cell::new(false));
let receiver_1_done_clone = receiver_1_done.clone();
// Once an item is received on the oneshot channel, it will immediately
// immediately make the second oneshot channel ready
tokio_current_thread.spawn(receiver.map_err(|_| unreachable!()).and_then(move |_| {
sender_2.send(()).unwrap();
receiver_1_done_clone.set(true);
Ok(())
}));
let receiver_2_done = Rc::new(Cell::new(false));
let receiver_2_done_clone = receiver_2_done.clone();
tokio_current_thread.spawn(receiver_2.map_err(|_| unreachable!()).and_then(move |_| {
receiver_2_done_clone.set(true);
Ok(())
}));
// The third receiver is only woken up from our Park implementation, it simulates
// e.g. a socket that first has to be polled to know if it is ready now
let receiver_3_done = Rc::new(Cell::new(false));
let receiver_3_done_clone = receiver_3_done.clone();
tokio_current_thread.spawn(receiver_3.map_err(|_| unreachable!()).and_then(move |_| {
receiver_3_done_clone.set(true);
Ok(())
}));
// First turn should've polled both and considered them not ready
let res = tokio_current_thread
.turn(Some(Duration::from_millis(0)))
.unwrap();
assert!(res.has_polled());
// Next turn should've polled nothing
let res = tokio_current_thread
.turn(Some(Duration::from_millis(0)))
.unwrap();
assert!(!res.has_polled());
assert!(!receiver_1_done.get());
assert!(!receiver_2_done.get());
assert!(!receiver_3_done.get());
// After this the receiver future will wake up the second receiver future,
// so there are pending futures again
sender.send(()).unwrap();
// Now the first receiver should be done, the second receiver should be ready
// to be polled again and the socket not yet
let res = tokio_current_thread.turn(None).unwrap();
assert!(res.has_polled());
assert!(receiver_1_done.get());
assert!(!receiver_2_done.get());
assert!(!receiver_3_done.get());
// Now let our park implementation know that it should send something to sender 3
send_now.set(true);
// This should resolve the second receiver directly, but also poll the socket
// and read the packet from it. If it didn't do both here, we would handle
// futures that are woken up from the reactor and directly unfairly and would
// favour the ones that are woken up directly.
let res = tokio_current_thread.turn(None).unwrap();
assert!(res.has_polled());
assert!(receiver_1_done.get());
assert!(receiver_2_done.get());
assert!(receiver_3_done.get());
// Don't send again
send_now.set(false);
// Now we should be idle and turning should not poll anything
assert!(tokio_current_thread.is_idle());
let res = tokio_current_thread.turn(None).unwrap();
assert!(!res.has_polled());
}
#[test]
fn spawn_from_other_thread() {
let mut current_thread = CurrentThread::new();
let handle = current_thread.handle();
let (sender, receiver) = oneshot::channel::<()>();
thread::spawn(move || {
handle
.spawn(lazy(move || {
sender.send(()).unwrap();
Ok(())
}))
.unwrap();
});
let _ = current_thread.block_on(receiver).unwrap();
}
#[test]
fn spawn_from_other_thread_unpark() {
use std::sync::mpsc::channel as mpsc_channel;
let mut current_thread = CurrentThread::new();
let handle = current_thread.handle();
let (sender_1, receiver_1) = oneshot::channel::<()>();
let (sender_2, receiver_2) = mpsc_channel::<()>();
thread::spawn(move || {
let _ = receiver_2.recv().unwrap();
handle
.spawn(lazy(move || {
sender_1.send(()).unwrap();
Ok(())
}))
.unwrap();
});
// Ensure that unparking the executor works correctly. It will first
// check if there are new futures (there are none), then execute the
// lazy future below which will cause the future to be spawned from
// the other thread. Then the executor will park but should be woken
// up because *now* we have a new future to schedule
let _ = current_thread
.block_on(
lazy(move || {
sender_2.send(()).unwrap();
Ok(())
})
.and_then(|_| receiver_1),
)
.unwrap();
}
#[test]
fn spawn_from_executor_with_handle() {
let mut current_thread = CurrentThread::new();
let handle = current_thread.handle();
let (tx, rx) = oneshot::channel();
current_thread.spawn(lazy(move || {
handle
.spawn(lazy(move || {
tx.send(()).unwrap();
Ok(())
}))
.unwrap();
Ok::<_, ()>(())
}));
current_thread.run();
rx.wait().unwrap();
}
fn ok() -> future::FutureResult<(), ()> {
future::ok(())
}
+53
View File
@@ -0,0 +1,53 @@
# 0.1.10 (February 4, 2020)
* Add `tokio 0.2.x` deprecation notice.
# 0.1.9 (November 27, 2019)
### Added
- Add `executor::set_default` which behaves like `with_default` but returns a
drop guard (#1725).
# 0.1.8 (June 2, 2019)
### Added
- Add `executor::exit` to allow other executors inside `threadpool::blocking` (#1155).
# 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
+28
View File
@@ -0,0 +1,28 @@
[package]
name = "tokio-executor"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.10"
documentation = "https://docs.rs/tokio-executor/0.1.10/tokio_executor"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://github.com/tokio-rs/tokio"
license = "MIT"
authors = ["Carl Lerche <[email protected]>"]
description = """
Future execution primitives
"""
keywords = ["futures", "tokio"]
categories = ["concurrency", "asynchronous"]
[dependencies]
crossbeam-utils = "0.7.0"
futures = "0.1.19"
[dev-dependencies]
tokio = "0.1.18"
+25
View File
@@ -0,0 +1,25 @@
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.
+53
View File
@@ -0,0 +1,53 @@
# tokio-executor
Task execution related traits and utilities.
This crate is **deprecated in tokio 0.2.x** and has been moved and refactored
into various places in the [`tokio::runtime`] module of the [`tokio`] crate.
[`tokio::runtime`]: https://docs.rs/tokio/latest/tokio/runtime/index.html
[`tokio`]: https://docs.rs/tokio/latest/tokio/index.html
[Documentation](https://docs.rs/tokio-executor/0.1.9/tokio_executor)
## Overview
In the Tokio execution model, futures are lazy. When a future is created, no
work is performed. In order for the work defined by the future to happen, the
future must be submitted to an executor. A future that is submitted to an
executor is called a "task".
The executor is responsible for ensuring that [`Future::poll`] is called
whenever the task is [notified]. Notification happens when the internal state of
a task transitions from "not ready" to ready. For example, a socket might have
received data and a call to `read` will now be able to succeed.
This crate provides traits and utilities that are necessary for building an
executor, including:
* The [`Executor`] trait describes the API for spawning a future onto an
executor.
* [`enter`] marks that the current thread is entering an execution
context. This prevents a second executor from accidentally starting from
within the context of one that is already running.
* [`DefaultExecutor`] spawns tasks onto the default executor for the current
context.
* [`Park`] abstracts over blocking and unblocking the current thread.
[`Executor`]: https://docs.rs/tokio-executor/0.1.9/tokio_executor/trait.Executor.html
[`enter`]: https://docs.rs/tokio-executor/0.1.9/tokio_executor/fn.enter.html
[`DefaultExecutor`]: https://docs.rs/tokio-executor/0.1.9/tokio_executor/struct.DefaultExecutor.html
[`Park`]: https://docs.rs/tokio-executor/0.1.9/tokio_executor/park/trait.Park.html
## 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.
+164
View File
@@ -0,0 +1,164 @@
use std::cell::Cell;
use std::error::Error;
use std::fmt;
use std::prelude::v1::*;
use futures::{self, Future};
thread_local!(static ENTERED: Cell<bool> = Cell::new(false));
/// Represents an executor context.
///
/// For more details, see [`enter` documentation](fn.enter.html)
pub struct Enter {
on_exit: Vec<Box<dyn Callback>>,
permanent: bool,
}
/// An error returned by `enter` if an execution scope has already been
/// entered.
pub struct EnterError {
_a: (),
}
impl fmt::Debug for EnterError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("EnterError")
.field("reason", &self.description())
.finish()
}
}
impl fmt::Display for EnterError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.description())
}
}
impl Error for EnterError {
fn description(&self) -> &str {
"attempted to run an executor while another executor is already running"
}
}
/// Marks the current thread as being within the dynamic extent of an
/// executor.
///
/// Executor implementations should call this function before blocking the
/// thread. If `None` is returned, the executor should fail by panicking or
/// taking some other action without blocking the current thread. This prevents
/// deadlocks due to multiple executors competing for the same thread.
///
/// # Error
///
/// Returns an error if the current thread is already marked
pub fn enter() -> Result<Enter, EnterError> {
ENTERED.with(|c| {
if c.get() {
Err(EnterError { _a: () })
} else {
c.set(true);
Ok(Enter {
on_exit: Vec::new(),
permanent: false,
})
}
})
}
// Forces the current "entered" state to be cleared while the closure
// is executed.
//
// # Warning
//
// This is hidden for a reason. Do not use without fully understanding
// executors. Misuing can easily cause your program to deadlock.
#[doc(hidden)]
pub fn exit<F: FnOnce() -> R, R>(f: F) -> R {
// Reset in case the closure panics
struct Reset;
impl Drop for Reset {
fn drop(&mut self) {
ENTERED.with(|c| {
c.set(true);
});
}
}
ENTERED.with(|c| {
debug_assert!(c.get());
c.set(false);
});
let reset = Reset;
let ret = f();
::std::mem::forget(reset);
ENTERED.with(|c| {
assert!(!c.get(), "closure claimed permanent executor");
c.set(true);
});
ret
}
impl Enter {
/// Register a callback to be invoked if and when the thread
/// ceased to act as an executor.
pub fn on_exit<F>(&mut self, f: F)
where
F: FnOnce() + 'static,
{
self.on_exit.push(Box::new(f));
}
/// Treat the remainder of execution on this thread as part of an
/// executor; used mostly for thread pool worker threads.
///
/// All registered `on_exit` callbacks are *dropped* without being
/// invoked.
pub fn make_permanent(mut self) {
self.permanent = true;
}
/// Blocks the thread on the specified future, returning the value with
/// which that future completes.
pub fn block_on<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error> {
futures::executor::spawn(f).wait_future()
}
}
impl fmt::Debug for Enter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Enter").finish()
}
}
impl Drop for Enter {
fn drop(&mut self) {
ENTERED.with(|c| {
assert!(c.get());
if self.permanent {
return;
}
for callback in self.on_exit.drain(..) {
callback.call();
}
c.set(false);
});
}
}
trait Callback: 'static {
fn call(self: Box<Self>);
}
impl<F: FnOnce() + 'static> Callback for F {
fn call(self: Box<Self>) {
(*self)()
}
}
+50
View File
@@ -0,0 +1,50 @@
use std::error::Error;
use std::fmt;
/// Errors returned by `Executor::spawn`.
///
/// Spawn errors should represent relatively rare scenarios. Currently, the two
/// scenarios represented by `SpawnError` are:
///
/// * An executor being at capacity or full. As such, the executor is not able
/// to accept a new future. This error state is expected to be transient.
/// * An executor has been shutdown and can no longer accept new futures. This
/// error state is expected to be permanent.
#[derive(Debug)]
pub struct SpawnError {
is_shutdown: bool,
}
impl SpawnError {
/// Return a new `SpawnError` reflecting a shutdown executor failure.
pub fn shutdown() -> Self {
SpawnError { is_shutdown: true }
}
/// Return a new `SpawnError` reflecting an executor at capacity failure.
pub fn at_capacity() -> Self {
SpawnError { is_shutdown: false }
}
/// Returns `true` if the error reflects a shutdown executor failure.
pub fn is_shutdown(&self) -> bool {
self.is_shutdown
}
/// Returns `true` if the error reflects an executor at capacity failure.
pub fn is_at_capacity(&self) -> bool {
!self.is_shutdown
}
}
impl fmt::Display for SpawnError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.description())
}
}
impl Error for SpawnError {
fn description(&self) -> &str {
"attempted to spawn task while the executor is at capacity or shut down"
}
}
+151
View File
@@ -0,0 +1,151 @@
use futures::Future;
use SpawnError;
/// A value that executes futures.
///
/// The [`spawn`] function is used to submit a future to an executor. Once
/// submitted, the executor takes ownership of the future and becomes
/// responsible for driving the future to completion.
///
/// The strategy employed by the executor to handle the future is less defined
/// and is left up to the `Executor` implementation. The `Executor` instance is
/// expected to call [`poll`] on the future once it has been notified, however
/// the "when" and "how" can vary greatly.
///
/// For example, the executor might be a thread pool, in which case a set of
/// threads have already been spawned up and the future is inserted into a
/// queue. A thread will acquire the future and poll it.
///
/// The `Executor` trait is only for futures that **are** `Send`. These are most
/// common. There currently is no trait that describes executors that operate
/// entirely on the current thread (i.e., are able to spawn futures that are not
/// `Send`). Note that single threaded executors can still implement `Executor`,
/// but only futures that are `Send` can be spawned via the trait.
///
/// This trait is primarily intended to implemented by executors and used to
/// back `tokio::spawn`. Libraries and applications **may** use this trait to
/// bound generics, but doing so will limit usage to futures that implement
/// `Send`. Instead, libraries and applications are recommended to use
/// [`TypedExecutor`] as a bound.
///
/// # Errors
///
/// The [`spawn`] function returns `Result` with an error type of `SpawnError`.
/// This error type represents the reason that the executor was unable to spawn
/// the future. The two current represented scenarios are:
///
/// * An executor being at capacity or full. As such, the executor is not able
/// to accept a new future. This error state is expected to be transient.
/// * An executor has been shutdown and can no longer accept new futures. This
/// error state is expected to be permanent.
///
/// If a caller encounters an at capacity error, the caller should try to shed
/// load. This can be as simple as dropping the future that was spawned.
///
/// If the caller encounters a shutdown error, the caller should attempt to
/// gracefully shutdown.
///
/// # Examples
///
/// ```rust
/// # extern crate futures;
/// # extern crate tokio_executor;
/// # use tokio_executor::Executor;
/// # fn docs(my_executor: &mut Executor) {
/// use futures::future::lazy;
/// my_executor.spawn(Box::new(lazy(|| {
/// println!("running on the executor");
/// Ok(())
/// }))).unwrap();
/// # }
/// # fn main() {}
/// ```
///
/// [`spawn`]: #tymethod.spawn
/// [`poll`]: https://docs.rs/futures/0.1/futures/future/trait.Future.html#tymethod.poll
/// [`TypedExecutor`]: ../trait.TypedExecutor.html
pub trait Executor {
/// Spawns a future object to run on this executor.
///
/// `future` is passed to the executor, which will begin running it. The
/// future may run on the current thread or another thread at the discretion
/// of the `Executor` implementation.
///
/// # Panics
///
/// Implementations are encouraged to avoid panics. However, panics are
/// permitted and the caller should check the implementation specific
/// documentation for more details on possible panics.
///
/// # Examples
///
/// ```rust
/// # extern crate futures;
/// # extern crate tokio_executor;
/// # use tokio_executor::Executor;
/// # fn docs(my_executor: &mut Executor) {
/// use futures::future::lazy;
/// my_executor.spawn(Box::new(lazy(|| {
/// println!("running on the executor");
/// Ok(())
/// }))).unwrap();
/// # }
/// # fn main() {}
/// ```
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError>;
/// Provides a best effort **hint** to whether or not `spawn` will succeed.
///
/// This function may return both false positives **and** false negatives.
/// If `status` returns `Ok`, then a call to `spawn` will *probably*
/// succeed, but may fail. If `status` returns `Err`, a call to `spawn` will
/// *probably* fail, but may succeed.
///
/// This allows a caller to avoid creating the task if the call to `spawn`
/// has a high likelihood of failing.
///
/// # Panics
///
/// This function must not panic. Implementers must ensure that panics do
/// not happen.
///
/// # Examples
///
/// ```rust
/// # extern crate futures;
/// # extern crate tokio_executor;
/// # use tokio_executor::Executor;
/// # fn docs(my_executor: &mut Executor) {
/// use futures::future::lazy;
///
/// if my_executor.status().is_ok() {
/// my_executor.spawn(Box::new(lazy(|| {
/// println!("running on the executor");
/// Ok(())
/// }))).unwrap();
/// } else {
/// println!("the executor is not in a good state");
/// }
/// # }
/// # fn main() {}
/// ```
fn status(&self) -> Result<(), SpawnError> {
Ok(())
}
}
impl<E: Executor + ?Sized> Executor for Box<E> {
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
(**self).spawn(future)
}
fn status(&self) -> Result<(), SpawnError> {
(**self).status()
}
}
+290
View File
@@ -0,0 +1,290 @@
use super::{Enter, Executor, SpawnError};
use futures::{future, Future};
use std::cell::Cell;
/// Executes futures on the default executor for the current execution context.
///
/// `DefaultExecutor` implements `Executor` and can be used to spawn futures
/// without referencing a specific executor.
///
/// When an executor starts, it sets the `DefaultExecutor` handle to point to an
/// executor (usually itself) that is used to spawn new tasks.
///
/// The current `DefaultExecutor` reference is tracked using a thread-local
/// variable and is set using `tokio_executor::with_default`
#[derive(Debug, Clone)]
pub struct DefaultExecutor {
_dummy: (),
}
/// Ensures that the executor is removed from the thread-local context
/// when leaving the scope. This handles cases that involve panicking.
#[derive(Debug)]
pub struct DefaultGuard {
_p: (),
}
impl DefaultExecutor {
/// Returns a handle to the default executor for the current context.
///
/// Futures may be spawned onto the default executor using this handle.
///
/// The returned handle will reference whichever executor is configured as
/// the default **at the time `spawn` is called**. This enables
/// `DefaultExecutor::current()` to be called before an execution context is
/// setup, then passed **into** an execution context before it is used.
///
/// This is also true for sending the handle across threads, so calling
/// `DefaultExecutor::current()` on thread A and then sending the result to
/// thread B will _not_ reference the default executor that was set on thread A.
pub fn current() -> DefaultExecutor {
DefaultExecutor { _dummy: () }
}
#[inline]
fn with_current<F: FnOnce(&mut dyn Executor) -> R, R>(f: F) -> Option<R> {
EXECUTOR.with(
|current_executor| match current_executor.replace(State::Active) {
State::Ready(executor_ptr) => {
let executor = unsafe { &mut *executor_ptr };
let result = f(executor);
current_executor.set(State::Ready(executor_ptr));
Some(result)
}
State::Empty | State::Active => None,
},
)
}
}
#[derive(Clone, Copy)]
enum State {
// default executor not defined
Empty,
// default executor is defined and ready to be used
Ready(*mut dyn Executor),
// default executor is currently active (used to detect recursive calls)
Active,
}
thread_local! {
/// Thread-local tracking the current executor
static EXECUTOR: Cell<State> = Cell::new(State::Empty)
}
// ===== impl DefaultExecutor =====
impl super::Executor for DefaultExecutor {
fn spawn(
&mut self,
future: Box<dyn Future<Item = (), Error = ()> + Send>,
) -> Result<(), SpawnError> {
DefaultExecutor::with_current(|executor| executor.spawn(future))
.unwrap_or_else(|| Err(SpawnError::shutdown()))
}
fn status(&self) -> Result<(), SpawnError> {
DefaultExecutor::with_current(|executor| executor.status())
.unwrap_or_else(|| Err(SpawnError::shutdown()))
}
}
impl<T> super::TypedExecutor<T> for DefaultExecutor
where
T: Future<Item = (), Error = ()> + Send + 'static,
{
fn spawn(&mut self, future: T) -> Result<(), SpawnError> {
super::Executor::spawn(self, Box::new(future))
}
fn status(&self) -> Result<(), SpawnError> {
super::Executor::status(self)
}
}
impl<T> future::Executor<T> for DefaultExecutor
where
T: Future<Item = (), Error = ()> + Send + 'static,
{
fn execute(&self, future: T) -> Result<(), future::ExecuteError<T>> {
if let Err(e) = super::Executor::status(self) {
let kind = if e.is_at_capacity() {
future::ExecuteErrorKind::NoCapacity
} else {
future::ExecuteErrorKind::Shutdown
};
return Err(future::ExecuteError::new(kind, future));
}
let _ = DefaultExecutor::with_current(|executor| executor.spawn(Box::new(future)));
Ok(())
}
}
// ===== global spawn fns =====
/// Submits a future for execution on the default executor -- usually a
/// threadpool.
///
/// Futures are lazy constructs. When they are defined, no work happens. In
/// order for the logic defined by the future to be run, the future must be
/// spawned on an executor. This function is the easiest way to do so.
///
/// This function must be called from an execution context, i.e. from a future
/// that has been already spawned onto an executor.
///
/// Once spawned, the future will execute. The details of how that happens is
/// left up to the executor instance. If the executor is a thread pool, the
/// future will be pushed onto a queue that a worker thread polls from. If the
/// executor is a "current thread" executor, the future might be polled
/// immediately from within the call to `spawn` or it might be pushed onto an
/// internal queue.
///
/// # Panics
///
/// This function will panic if the default executor is not set or if spawning
/// onto the default executor returns an error. To avoid the panic, use the
/// `DefaultExecutor` handle directly.
///
/// # Examples
///
/// ```rust
/// # extern crate futures;
/// # extern crate tokio_executor;
/// # use tokio_executor::spawn;
/// # pub fn dox() {
/// use futures::future::lazy;
///
/// spawn(lazy(|| {
/// println!("running on the default executor");
/// Ok(())
/// }));
/// # }
/// # pub fn main() {}
/// ```
pub fn spawn<T>(future: T)
where
T: Future<Item = (), Error = ()> + Send + 'static,
{
DefaultExecutor::current().spawn(Box::new(future)).unwrap()
}
/// Set the default executor for the duration of the closure
///
/// # Panics
///
/// This function panics if there already is a default executor set.
pub fn with_default<T, F, R>(executor: &mut T, enter: &mut Enter, f: F) -> R
where
T: Executor,
F: FnOnce(&mut Enter) -> R,
{
unsafe fn hide_lt<'a>(p: *mut (dyn Executor + 'a)) -> *mut (dyn Executor + 'static) {
use std::mem;
mem::transmute(p)
}
EXECUTOR.with(|cell| {
match cell.get() {
State::Ready(_) | State::Active => {
panic!("default executor already set for execution context")
}
_ => {}
}
// Ensure that the executor is removed from the thread-local context
// when leaving the scope. This handles cases that involve panicking.
struct Reset<'a>(&'a Cell<State>);
impl<'a> Drop for Reset<'a> {
fn drop(&mut self) {
self.0.set(State::Empty);
}
}
let _reset = Reset(cell);
// While scary, this is safe. The function takes a
// `&mut Executor`, which guarantees that the reference lives for the
// duration of `with_default`.
//
// Because we are always clearing the TLS value at the end of the
// function, we can cast the reference to 'static which thread-local
// cells require.
let executor = unsafe { hide_lt(executor as &mut _ as *mut _) };
cell.set(State::Ready(executor));
f(enter)
})
}
/// Sets `executor` as the default executor, returning a guard that unsets it when
/// dropped.
///
/// # Panics
///
/// This function panics if there already is a default executor set.
pub fn set_default<T>(executor: T) -> DefaultGuard
where
T: Executor + 'static,
{
EXECUTOR.with(|cell| {
match cell.get() {
State::Ready(_) | State::Active => {
panic!("default executor already set for execution context")
}
_ => {}
}
// Ensure that the executor will outlive the call to set_default, even
// if the drop guard is never dropped due to calls to `mem::forget` or
// similar.
let executor = Box::new(executor);
cell.set(State::Ready(Box::into_raw(executor)));
});
DefaultGuard { _p: () }
}
impl Drop for DefaultGuard {
fn drop(&mut self) {
let _ = EXECUTOR.try_with(|cell| {
if let State::Ready(prev) = cell.replace(State::Empty) {
// drop the previous executor.
unsafe {
let prev = Box::from_raw(prev);
drop(prev);
};
}
});
}
}
#[cfg(test)]
mod tests {
use super::{with_default, DefaultExecutor, Executor};
#[test]
fn default_executor_is_send_and_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<DefaultExecutor>();
}
#[test]
fn nested_default_executor_status() {
let mut enter = super::super::enter().unwrap();
let mut executor = DefaultExecutor::current();
let result = with_default(&mut executor, &mut enter, |_| {
DefaultExecutor::current().status()
});
assert!(result.err().unwrap().is_shutdown())
}
}
+68
View File
@@ -0,0 +1,68 @@
#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-executor/0.1.10")]
//! Task execution related traits and utilities.
//!
//! In the Tokio execution model, futures are lazy. When a future is created, no
//! work is performed. In order for the work defined by the future to happen,
//! the future must be submitted to an executor. A future that is submitted to
//! an executor is called a "task".
//!
//! The executor is responsible for ensuring that [`Future::poll`] is called
//! whenever the task is notified. Notification happens when the internal
//! state of a task transitions from *not ready* to *ready*. For example, a
//! socket might have received data and a call to `read` will now be able to
//! succeed.
//!
//! This crate provides traits and utilities that are necessary for building an
//! executor, including:
//!
//! * The [`Executor`] trait spawns future object onto an executor.
//!
//! * The [`TypedExecutor`] trait spawns futures of a specific type onto an
//! executor. This is used to be generic over executors that spawn futures
//! that are either `Send` or `!Send` or implement executors that apply to
//! specific futures.
//!
//! * [`enter`] marks that the current thread is entering an execution
//! context. This prevents a second executor from accidentally starting from
//! within the context of one that is already running.
//!
//! * [`DefaultExecutor`] spawns tasks onto the default executor for the current
//! context.
//!
//! * [`Park`] abstracts over blocking and unblocking the current thread.
//!
//! # Implementing an executor
//!
//! Executors should always implement `TypedExecutor`. This usually is the bound
//! that applications and libraries will use when generic over an executor. See
//! the [trait documentation][`TypedExecutor`] for more details.
//!
//! If the executor is able to spawn all futures that are `Send`, then the
//! executor should also implement the `Executor` trait. This trait is rarely
//! used directly by applications and libraries. Instead, `tokio::spawn` is
//! configured to dispatch to type that implements `Executor`.
//!
//! [`Executor`]: trait.Executor.html
//! [`TypedExecutor`]: trait.TypedExecutor.html
//! [`enter`]: fn.enter.html
//! [`DefaultExecutor`]: struct.DefaultExecutor.html
//! [`Park`]: park/index.html
//! [`Future::poll`]: https://docs.rs/futures/0.1/futures/future/trait.Future.html#tymethod.poll
extern crate crossbeam_utils;
extern crate futures;
mod enter;
mod error;
mod executor;
mod global;
pub mod park;
mod typed;
pub use enter::{enter, exit, Enter, EnterError};
pub use error::SpawnError;
pub use executor::Executor;
pub use global::{set_default, spawn, with_default, DefaultExecutor, DefaultGuard};
pub use typed::TypedExecutor;
+226
View File
@@ -0,0 +1,226 @@
//! Abstraction over blocking and unblocking the current thread.
//!
//! Provides an abstraction over blocking the current thread. This is similar to
//! the park / unpark constructs provided by [`std`] but made generic. This
//! allows embedding custom functionality to perform when the thread is blocked.
//!
//! A blocked [`Park`][p] instance is unblocked by calling [`unpark`] on its
//! [`Unpark`][up] handle.
//!
//! The [`ParkThread`] struct implements [`Park`][p] using
//! [`thread::park`][`std`] to put the thread to sleep. The Tokio reactor also
//! implements park, but uses [`mio::Poll`][mio] to block the thread instead.
//!
//! The [`Park`][p] trait is composable. A timer implementation might decorate a
//! [`Park`][p] implementation by checking if any timeouts have elapsed after
//! the inner [`Park`][p] implementation unblocks.
//!
//! # Model
//!
//! Conceptually, each [`Park`][p] instance has an associated token, which is
//! initially not present:
//!
//! * The [`park`] method blocks the current thread unless or until the token
//! is available, at which point it atomically consumes the token.
//! * The [`unpark`] method atomically makes the token available if it wasn't
//! already.
//!
//! Some things to note:
//!
//! * If [`unpark`] is called before [`park`], the next call to [`park`] will
//! **not** block the thread.
//! * **Spurious** wakeups are permitted, i.e., the [`park`] method may unblock
//! even if [`unpark`] was not called.
//! * [`park_timeout`] does the same as [`park`] but allows specifying a maximum
//! time to block the thread for.
//!
//! [`std`]: https://doc.rust-lang.org/std/thread/fn.park.html
//! [`thread::park`]: https://doc.rust-lang.org/std/thread/fn.park.html
//! [`ParkThread`]: struct.ParkThread.html
//! [p]: trait.Park.html
//! [`park`]: trait.Park.html#tymethod.park
//! [`park_timeout`]: trait.Park.html#tymethod.park_timeout
//! [`unpark`]: trait.Unpark.html#tymethod.unpark
//! [up]: trait.Unpark.html
//! [mio]: https://docs.rs/mio/0.6/mio/struct.Poll.html
use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::Arc;
use std::time::Duration;
use crossbeam_utils::sync::{Parker, Unparker};
/// Block the current thread.
///
/// See [module documentation][mod] for more details.
///
/// [mod]: ../index.html
pub trait Park {
/// Unpark handle type for the `Park` implementation.
type Unpark: Unpark;
/// Error returned by `park`
type Error;
/// Get a new `Unpark` handle associated with this `Park` instance.
fn unpark(&self) -> Self::Unpark;
/// Block the current thread unless or until the token is available.
///
/// A call to `park` does not guarantee that the thread will remain blocked
/// forever, and callers should be prepared for this possibility. This
/// function may wakeup spuriously for any reason.
///
/// See [module documentation][mod] for more details.
///
/// # Panics
///
/// This function **should** not panic, but ultimately, panics are left as
/// an implementation detail. Refer to the documentation for the specific
/// `Park` implementation
///
/// [mod]: ../index.html
fn park(&mut self) -> Result<(), Self::Error>;
/// Park the current thread for at most `duration`.
///
/// This function is the same as `park` but allows specifying a maximum time
/// to block the thread for.
///
/// Same as `park`, there is no guarantee that the thread will remain
/// blocked for any amount of time. Spurious wakeups are permitted for any
/// reason.
///
/// See [module documentation][mod] for more details.
///
/// # Panics
///
/// This function **should** not panic, but ultimately, panics are left as
/// an implementation detail. Refer to the documentation for the specific
/// `Park` implementation
///
/// [mod]: ../index.html
fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error>;
}
/// Unblock a thread blocked by the associated [`Park`] instance.
///
/// See [module documentation][mod] for more details.
///
/// [mod]: ../index.html
/// [`Park`]: trait.Park.html
pub trait Unpark: Sync + Send + 'static {
/// Unblock a thread that is blocked by the associated `Park` handle.
///
/// Calling `unpark` atomically makes available the unpark token, if it is
/// not already available.
///
/// See [module documentation][mod] for more details.
///
/// # Panics
///
/// This function **should** not panic, but ultimately, panics are left as
/// an implementation detail. Refer to the documentation for the specific
/// `Unpark` implementation
///
/// [mod]: ../index.html
fn unpark(&self);
}
impl Unpark for Box<dyn Unpark> {
fn unpark(&self) {
(**self).unpark()
}
}
impl Unpark for Arc<dyn Unpark> {
fn unpark(&self) {
(**self).unpark()
}
}
/// Blocks the current thread using a condition variable.
///
/// Implements the [`Park`] functionality by using a condition variable. An
/// atomic variable is also used to avoid using the condition variable if
/// possible.
///
/// The condition variable is cached in a thread-local variable and is shared
/// across all `ParkThread` instances created on the same thread. This also
/// means that an instance of `ParkThread` might be unblocked by a handle
/// associated with a different `ParkThread` instance.
#[derive(Debug)]
pub struct ParkThread {
_anchor: PhantomData<Rc<()>>,
}
/// Error returned by [`ParkThread`]
///
/// This currently is never returned, but might at some point in the future.
///
/// [`ParkThread`]: struct.ParkThread.html
#[derive(Debug)]
pub struct ParkError {
_p: (),
}
/// Unblocks a thread that was blocked by `ParkThread`.
#[derive(Clone, Debug)]
pub struct UnparkThread {
inner: Unparker,
}
thread_local! {
static CURRENT_PARKER: Parker = Parker::new();
}
// ===== impl ParkThread =====
impl ParkThread {
/// Create a new `ParkThread` handle for the current thread.
///
/// This type cannot be moved to other threads, so it should be created on
/// the thread that the caller intends to park.
pub fn new() -> ParkThread {
ParkThread {
_anchor: PhantomData,
}
}
/// Get a reference to the `ParkThread` handle for this thread.
fn with_current<F, R>(&self, f: F) -> R
where
F: FnOnce(&Parker) -> R,
{
CURRENT_PARKER.with(|inner| f(inner))
}
}
impl Park for ParkThread {
type Unpark = UnparkThread;
type Error = ParkError;
fn unpark(&self) -> Self::Unpark {
let inner = self.with_current(|inner| inner.unparker().clone());
UnparkThread { inner }
}
fn park(&mut self) -> Result<(), Self::Error> {
self.with_current(|inner| inner.park());
Ok(())
}
fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error> {
self.with_current(|inner| inner.park_timeout(duration));
Ok(())
}
}
// ===== impl UnparkThread =====
impl Unpark for UnparkThread {
fn unpark(&self) {
self.inner.unpark();
}
}
+181
View File
@@ -0,0 +1,181 @@
use SpawnError;
/// A value that spawns futures of a specific type.
///
/// The trait is generic over `T`: the type of future that can be spawened. This
/// is useful for implementing an executor that is only able to spawn a specific
/// type of future.
///
/// The [`spawn`] function is used to submit the future to the executor. Once
/// submitted, the executor takes ownership of the future and becomes
/// responsible for driving the future to completion.
///
/// This trait is useful as a bound for applications and libraries in order to
/// be generic over futures that are `Send` vs. `!Send`.
///
/// # Examples
///
/// Consider a function that provides an API for draining a `Stream` in the
/// background. To do this, a task must be spawned to perform the draining. As
/// such, the function takes a stream and an executor on which the background
/// task is spawned.
///
/// ```rust
/// #[macro_use]
/// extern crate futures;
/// extern crate tokio;
///
/// use futures::{Future, Stream, Poll};
/// use tokio::executor::TypedExecutor;
/// use tokio::sync::oneshot;
///
/// pub fn drain<T, E>(stream: T, executor: &mut E)
/// -> impl Future<Item = (), Error = ()>
/// where
/// T: Stream,
/// E: TypedExecutor<Drain<T>>
/// {
/// let (tx, rx) = oneshot::channel();
///
/// executor.spawn(Drain {
/// stream,
/// tx: Some(tx),
/// }).unwrap();
///
/// rx.map_err(|_| ())
/// }
///
/// // The background task
/// pub struct Drain<T: Stream> {
/// stream: T,
/// tx: Option<oneshot::Sender<()>>,
/// }
///
/// impl<T: Stream> Future for Drain<T> {
/// type Item = ();
/// type Error = ();
///
/// fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
/// loop {
/// let item = try_ready!(
/// self.stream.poll()
/// .map_err(|_| ())
/// );
///
/// if item.is_none() { break; }
/// }
///
/// self.tx.take().unwrap().send(()).map_err(|_| ());
/// Ok(().into())
/// }
/// }
/// # pub fn main() {}
/// ```
///
/// By doing this, the `drain` fn can accept a stream that is `!Send` as long as
/// the supplied executor is able to spawn `!Send` types.
pub trait TypedExecutor<T> {
/// Spawns a future to run on this executor.
///
/// `future` is passed to the executor, which will begin running it. The
/// executor takes ownership of the future and becomes responsible for
/// driving the future to completion.
///
/// # Panics
///
/// Implementations are encouraged to avoid panics. However, panics are
/// permitted and the caller should check the implementation specific
/// documentation for more details on possible panics.
///
/// # Examples
///
/// ```rust
/// # extern crate futures;
/// # extern crate tokio_executor;
/// # use tokio_executor::TypedExecutor;
/// # use futures::{Future, Poll};
/// fn example<T>(my_executor: &mut T)
/// where
/// T: TypedExecutor<MyFuture>,
/// {
/// my_executor.spawn(MyFuture).unwrap();
/// }
///
/// struct MyFuture;
///
/// impl Future for MyFuture {
/// type Item = ();
/// type Error = ();
///
/// fn poll(&mut self) -> Poll<(), ()> {
/// println!("running on the executor");
/// Ok(().into())
/// }
/// }
/// # fn main() {}
/// ```
fn spawn(&mut self, future: T) -> Result<(), SpawnError>;
/// Provides a best effort **hint** to whether or not `spawn` will succeed.
///
/// This function may return both false positives **and** false negatives.
/// If `status` returns `Ok`, then a call to `spawn` will *probably*
/// succeed, but may fail. If `status` returns `Err`, a call to `spawn` will
/// *probably* fail, but may succeed.
///
/// This allows a caller to avoid creating the task if the call to `spawn`
/// has a high likelihood of failing.
///
/// # Panics
///
/// This function must not panic. Implementers must ensure that panics do
/// not happen.
///
/// # Examples
///
/// ```rust
/// # extern crate futures;
/// # extern crate tokio_executor;
/// # use tokio_executor::TypedExecutor;
/// # use futures::{Future, Poll};
/// fn example<T>(my_executor: &mut T)
/// where
/// T: TypedExecutor<MyFuture>,
/// {
/// if my_executor.status().is_ok() {
/// my_executor.spawn(MyFuture).unwrap();
/// } else {
/// println!("the executor is not in a good state");
/// }
/// }
///
/// struct MyFuture;
///
/// impl Future for MyFuture {
/// type Item = ();
/// type Error = ();
///
/// fn poll(&mut self) -> Poll<(), ()> {
/// println!("running on the executor");
/// Ok(().into())
/// }
/// }
/// # fn main() {}
/// ```
fn status(&self) -> Result<(), SpawnError> {
Ok(())
}
}
impl<E, T> TypedExecutor<T> for Box<E>
where
E: TypedExecutor<T>,
{
fn spawn(&mut self, future: T) -> Result<(), SpawnError> {
(**self).spawn(future)
}
fn status(&self) -> Result<(), SpawnError> {
(**self).status()
}
}
+29
View File
@@ -0,0 +1,29 @@
extern crate futures;
extern crate tokio_executor;
use futures::{future::lazy, Future};
use tokio_executor::DefaultExecutor;
mod out_of_executor_context {
use super::*;
use tokio_executor::Executor;
fn test<F, E>(spawn: F)
where
F: Fn(Box<dyn Future<Item = (), Error = ()> + Send>) -> Result<(), E>,
{
let res = spawn(Box::new(lazy(|| Ok(()))));
assert!(res.is_err());
}
#[test]
fn spawn() {
test(|f| DefaultExecutor::current().spawn(f));
}
#[test]
fn execute() {
use futures::future::Executor as FuturesExecutor;
test(|f| DefaultExecutor::current().execute(f));
}
}
+36
View File
@@ -0,0 +1,36 @@
# 0.1.7 (February 4, 2020)
* Add `tokio 0.2.x` deprecation notice.
# 0.1.6 (March 1, 2019)
### Added
- File::try_clone() (#850).
- Async equivalent of read / write file helpers being added to `std` (#896).
# 0.1.5 (January 6, 2019)
* Add examples to `File` API docs (#786).
# 0.1.4 (October 23, 2018)
* Provide `File::from_std` (#696).
# 0.1.3 (August 6, 2018)
* Add async equivalents to most of `std::fs` (#494).
# 0.1.2 (July 11, 2018)
* Add `metadata` and `File::metadata` ([#433](https://github.com/tokio-rs/tokio/pull/433), [#385](https://github.com/tokio-rs/tokio/pull/385))
* Add `File::seek` ([#434](https://github.com/tokio-rs/tokio/pull/434))
# 0.1.1 (June 13, 2018)
* Add `OpenOptions` ([#390](https://github.com/tokio-rs/tokio/pull/390))
* Add `into_std` to `File` ([#403](https://github.com/tokio-rs/tokio/pull/403))
* Use `tokio-codec` in examples
# 0.1.0 (May 2, 2018)
* Initial release
+34
View File
@@ -0,0 +1,34 @@
[package]
name = "tokio-fs"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.7"
authors = ["Carl Lerche <[email protected]>"]
license = "MIT"
readme = "README.md"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://tokio.rs"
documentation = "https://docs.rs/tokio-fs/0.1.7/tokio_fs"
description = """
Filesystem API for Tokio.
"""
keywords = ["tokio", "futures", "fs", "file", "async"]
categories = ["asynchronous", "network-programming", "filesystem"]
[dependencies]
futures = "0.1.21"
tokio-threadpool = "0.1.3"
tokio-io = "0.1.6"
[dev-dependencies]
rand = "0.7"
tempfile = "~3.1.0"
tokio-io = "0.1.6"
tokio-codec = "0.1.0"
tokio = "0.1.7"
+25
View File
@@ -0,0 +1,25 @@
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.
+25
View File
@@ -0,0 +1,25 @@
# Tokio FS
Asynchronous filesystem manipulation operations (and stdin, stdout, stderr).
This crate has been **deprecated in tokio 0.2.x** and has been moved into
[`tokio::fs`] behind the `fs` [feature flag].
[`tokio::fs`]: https://docs.rs/tokio/latest/tokio/fs/index.html
[feature flag]: https://docs.rs/tokio/latest/tokio/index.html#feature-flags
[Documentation](https://docs.rs/tokio-fs/0.1.6/tokio_fs)
## Overview
This crate provides filesystem manipulation facilities for usage with Tokio.
## 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.
+47
View File
@@ -0,0 +1,47 @@
//! Echo everything received on STDIN to STDOUT.
#![deny(deprecated)]
extern crate futures;
extern crate tokio_codec;
extern crate tokio_fs;
extern crate tokio_threadpool;
use tokio_codec::{FramedRead, FramedWrite, LinesCodec};
use tokio_fs::{stderr, stdin, stdout};
use tokio_threadpool::Builder;
use futures::{Future, Sink, Stream};
use std::io;
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = Builder::new().pool_size(1).build();
pool.spawn({
let input = FramedRead::new(stdin(), LinesCodec::new());
let output = FramedWrite::new(stdout(), LinesCodec::new()).with(|line: String| {
let mut out = "OUT: ".to_string();
out.push_str(&line);
Ok::<_, io::Error>(out)
});
let error = FramedWrite::new(stderr(), LinesCodec::new()).with(|line: String| {
let mut out = "ERR: ".to_string();
out.push_str(&line);
Ok::<_, io::Error>(out)
});
let dst = output.fanout(error);
input
.forward(dst)
.map(|_| ())
.map_err(|e| panic!("io error = {:?}", e))
});
pool.shutdown_on_idle()
.wait()
.map_err(|_| "failed to shutdown the thread pool")?;
Ok(())
}
+44
View File
@@ -0,0 +1,44 @@
use std::fs;
use std::io;
use std::path::Path;
use futures::{Future, Poll};
/// Creates a new, empty directory at the provided path
///
/// This is an async version of [`std::fs::create_dir`][std]
///
/// [std]: https://doc.rust-lang.org/std/fs/fn.create_dir.html
pub fn create_dir<P: AsRef<Path>>(path: P) -> CreateDirFuture<P> {
CreateDirFuture::new(path)
}
/// Future returned by `create_dir`.
#[derive(Debug)]
pub struct CreateDirFuture<P>
where
P: AsRef<Path>,
{
path: P,
}
impl<P> CreateDirFuture<P>
where
P: AsRef<Path>,
{
fn new(path: P) -> CreateDirFuture<P> {
CreateDirFuture { path: path }
}
}
impl<P> Future for CreateDirFuture<P>
where
P: AsRef<Path>,
{
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
::blocking_io(|| fs::create_dir(&self.path))
}
}
+45
View File
@@ -0,0 +1,45 @@
use std::fs;
use std::io;
use std::path::Path;
use futures::{Future, Poll};
/// Recursively create a directory and all of its parent components if they
/// are missing.
///
/// This is an async version of [`std::fs::create_dir_all`][std]
///
/// [std]: https://doc.rust-lang.org/std/fs/fn.create_dir_all.html
pub fn create_dir_all<P: AsRef<Path>>(path: P) -> CreateDirAllFuture<P> {
CreateDirAllFuture::new(path)
}
/// Future returned by `create_dir_all`.
#[derive(Debug)]
pub struct CreateDirAllFuture<P>
where
P: AsRef<Path>,
{
path: P,
}
impl<P> CreateDirAllFuture<P>
where
P: AsRef<Path>,
{
fn new(path: P) -> CreateDirAllFuture<P> {
CreateDirAllFuture { path: path }
}
}
impl<P> Future for CreateDirAllFuture<P>
where
P: AsRef<Path>,
{
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
::blocking_io(|| fs::create_dir_all(&self.path))
}
}
+37
View File
@@ -0,0 +1,37 @@
use super::File;
use futures::{Future, Poll};
use std::io;
/// Future returned by `File::try_clone`.
///
/// Clones a file handle into two file handles.
///
/// # Panics
///
/// Will panic if polled after returning an item or error.
#[derive(Debug)]
pub struct CloneFuture {
file: Option<File>,
}
impl CloneFuture {
pub(crate) fn new(file: File) -> Self {
Self { file: Some(file) }
}
}
impl Future for CloneFuture {
type Item = (File, File);
type Error = (File, io::Error);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.file
.as_mut()
.expect("Cannot poll `CloneFuture` after it resolves")
.poll_try_clone()
.map(|inner| inner.map(|cloned| (self.file.take().unwrap(), cloned)))
.map_err(|err| (self.file.take().unwrap(), err))
}
}
+37
View File
@@ -0,0 +1,37 @@
use super::File;
use futures::{Future, Poll};
use std::fs::File as StdFile;
use std::io;
use std::path::Path;
/// Future returned by `File::create` and resolves to a `File` instance.
#[derive(Debug)]
pub struct CreateFuture<P> {
path: P,
}
impl<P> CreateFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
pub(crate) fn new(path: P) -> Self {
CreateFuture { path }
}
}
impl<P> Future for CreateFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
type Item = File;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let std = try_ready!(::blocking_io(|| StdFile::create(&self.path)));
let file = File::from_std(std);
Ok(file.into())
}
}
+37
View File
@@ -0,0 +1,37 @@
use super::File;
use futures::{Future, Poll};
use std::fs::File as StdFile;
use std::fs::Metadata;
use std::io;
const POLL_AFTER_RESOLVE: &str = "Cannot poll MetadataFuture after it resolves";
/// Future returned by `File::metadata` and resolves to a `(File, Metadata)` instance.
#[derive(Debug)]
pub struct MetadataFuture {
file: Option<File>,
}
impl MetadataFuture {
pub(crate) fn new(file: File) -> Self {
MetadataFuture { file: Some(file) }
}
fn std(&mut self) -> &mut StdFile {
self.file.as_mut().expect(POLL_AFTER_RESOLVE).std()
}
}
impl Future for MetadataFuture {
type Item = (File, Metadata);
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let metadata = try_ready!(::blocking_io(|| StdFile::metadata(self.std())));
let file = self.file.take().expect(POLL_AFTER_RESOLVE);
Ok((file, metadata).into())
}
}
+559
View File
@@ -0,0 +1,559 @@
//! Types for working with [`File`].
//!
//! [`File`]: file/struct.File.html
mod clone;
mod create;
mod metadata;
mod open;
mod open_options;
mod seek;
pub use self::clone::CloneFuture;
pub use self::create::CreateFuture;
pub use self::metadata::MetadataFuture;
pub use self::open::OpenFuture;
pub use self::open_options::OpenOptions;
pub use self::seek::SeekFuture;
use tokio_io::{AsyncRead, AsyncWrite};
use futures::Poll;
use std::fs::{File as StdFile, Metadata, Permissions};
use std::io::{self, Read, Seek, Write};
use std::path::Path;
/// A reference to an open file on the filesystem.
///
/// This is a specialized version of [`std::fs::File`][std] for usage from the
/// Tokio runtime.
///
/// An instance of a `File` can be read and/or written depending on what options
/// it was opened with. Files also implement Seek to alter the logical cursor
/// that the file contains internally.
///
/// Files are automatically closed when they go out of scope.
///
/// [std]: https://doc.rust-lang.org/std/fs/struct.File.html
///
/// # Examples
///
/// Create a new file and asynchronously write bytes to it:
///
/// ```no_run
/// extern crate tokio;
///
/// use tokio::prelude::{AsyncWrite, Future};
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|mut file| file.poll_write(b"hello, world!"))
/// .map(|res| {
/// println!("{:?}", res);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
///
/// Read the contents of a file into a buffer
///
/// ```no_run
/// extern crate tokio;
///
/// use tokio::prelude::{AsyncRead, Future};
///
/// fn main() {
/// let task = tokio::fs::File::open("foo.txt")
/// .and_then(|mut file| {
/// let mut contents = vec![];
/// file.read_buf(&mut contents)
/// .map(|res| {
/// println!("{:?}", res);
/// })
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
/// tokio::run(task);
/// }
/// ```
#[derive(Debug)]
pub struct File {
std: Option<StdFile>,
}
impl File {
/// Attempts to open a file in read-only mode.
///
/// See [`OpenOptions`] for more details.
///
/// [`OpenOptions`]: struct.OpenOptions.html
///
/// # Errors
///
/// `OpenFuture` results in an error if called from outside of the Tokio
/// runtime or if the underlying [`open`] call results in an error.
///
/// [`open`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.open
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
/// fn main() {
/// let task = tokio::fs::File::open("foo.txt").and_then(|file| {
/// // do something with the file ...
/// file.metadata().map(|md| println!("{:?}", md))
/// }).map_err(|e| {
/// // handle errors
/// eprintln!("IO error: {:?}", e);
/// });
/// tokio::run(task);
/// }
/// ```
pub fn open<P>(path: P) -> OpenFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
OpenOptions::new().read(true).open(path)
}
/// Opens a file in write-only mode.
///
/// This function will create a file if it does not exist, and will truncate
/// it if it does.
///
/// See [`OpenOptions`] for more details.
///
/// [`OpenOptions`]: struct.OpenOptions.html
///
/// # Errors
///
/// `CreateFuture` results in an error if called from outside of the Tokio
/// runtime or if the underlying [`create`] call results in an error.
///
/// [`create`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.create
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|file| {
/// // do something with the created file ...
/// file.metadata().map(|md| println!("{:?}", md))
/// }).map_err(|e| {
/// // handle errors
/// eprintln!("IO error: {:?}", e);
/// });
/// tokio::run(task);
/// }
/// ```
pub fn create<P>(path: P) -> CreateFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
CreateFuture::new(path)
}
/// Convert a [`std::fs::File`][std] to a [`tokio_fs::File`][file].
///
/// [std]: https://doc.rust-lang.org/std/fs/struct.File.html
/// [file]: struct.File.html
///
/// Examples
/// ```no_run
/// # extern crate tokio;
/// use std::fs::File;
///
/// fn main() {
/// let std_file = File::open("foo.txt").unwrap();
/// let file = tokio::fs::File::from_std(std_file);
/// }
/// ```
pub fn from_std(std: StdFile) -> File {
File { std: Some(std) }
}
/// Seek to an offset, in bytes, in a stream.
///
/// A seek beyond the end of a stream is allowed, but implementation
/// defined.
///
/// If the seek operation completed successfully, this method returns the
/// new position from the start of the stream. That position can be used
/// later with `SeekFrom::Start`.
///
/// # Errors
///
/// Seeking to a negative offset is considered an error.
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
/// use std::io::SeekFrom;
///
/// fn main() {
/// let task = tokio::fs::File::open("foo.txt")
/// // move cursor 6 bytes from the start of the file
/// .and_then(|mut file| file.poll_seek(SeekFrom::Start(6)))
/// .map(|res| {
/// println!("{:?}", res);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn poll_seek(&mut self, pos: io::SeekFrom) -> Poll<u64, io::Error> {
::blocking_io(|| self.std().seek(pos))
}
/// Seek to an offset, in bytes, in a stream.
///
/// Similar to `poll_seek`, but returning a `Future`.
///
/// This method consumes the `File` and returns it back when the future
/// completes.
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
/// use std::io::SeekFrom;
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|file| file.seek(SeekFrom::Start(6)))
/// .map(|file| {
/// // handle returned file ..
/// # println!("{:?}", file);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn seek(self, pos: io::SeekFrom) -> SeekFuture {
SeekFuture::new(self, pos)
}
/// Attempts to sync all OS-internal metadata to disk.
///
/// This function will attempt to ensure that all in-core data reaches the
/// filesystem before returning.
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::{AsyncWrite, Future};
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|mut file| {
/// file.poll_write(b"hello, world!")?;
/// file.poll_sync_all()
/// })
/// .map(|res| {
/// // handle returned result ..
/// # println!("{:?}", res);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn poll_sync_all(&mut self) -> Poll<(), io::Error> {
::blocking_io(|| self.std().sync_all())
}
/// This function is similar to `poll_sync_all`, except that it may not
/// synchronize file metadata to the filesystem.
///
/// This is intended for use cases that must synchronize content, but don't
/// need the metadata on disk. The goal of this method is to reduce disk
/// operations.
///
/// Note that some platforms may simply implement this in terms of `poll_sync_all`.
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::{AsyncWrite, Future};
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|mut file| {
/// file.poll_write(b"hello, world!")?;
/// file.poll_sync_data()
/// })
/// .map(|res| {
/// // handle returned result ..
/// # println!("{:?}", res);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn poll_sync_data(&mut self) -> Poll<(), io::Error> {
::blocking_io(|| self.std().sync_data())
}
/// Truncates or extends the underlying file, updating the size of this file to become size.
///
/// If the size is less than the current file's size, then the file will be
/// shrunk. If it is greater than the current file's size, then the file
/// will be extended to size and have all of the intermediate data filled in
/// with 0s.
///
/// # Errors
///
/// This function will return an error if the file is not opened for
/// writing.
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|mut file| {
/// file.poll_set_len(10)
/// })
/// .map(|res| {
/// // handle returned result ..
/// # println!("{:?}", res);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn poll_set_len(&mut self, size: u64) -> Poll<(), io::Error> {
::blocking_io(|| self.std().set_len(size))
}
/// Queries metadata about the underlying file.
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|file| file.metadata())
/// .map(|metadata| {
/// println!("{:?}", metadata);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn metadata(self) -> MetadataFuture {
MetadataFuture::new(self)
}
/// Queries metadata about the underlying file.
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|mut file| file.poll_metadata())
/// .map(|metadata| {
/// // metadata is of type Async::Ready<Metadata>
/// println!("{:?}", metadata);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn poll_metadata(&mut self) -> Poll<Metadata, io::Error> {
::blocking_io(|| self.std().metadata())
}
/// Create a new `File` instance that shares the same underlying file handle
/// as the existing `File` instance. Reads, writes, and seeks will affect both
/// File instances simultaneously.
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|mut file| file.poll_try_clone())
/// .map(|clone| {
/// // do something with the clone
/// # println!("{:?}", clone);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn poll_try_clone(&mut self) -> Poll<File, io::Error> {
::blocking_io(|| {
let std = self.std().try_clone()?;
Ok(File::from_std(std))
})
}
/// Create a new `File` instance that shares the same underlying file handle
/// as the existing `File` instance. Reads, writes, and seeks will affect both
/// File instances simultaneously.
///
/// # Examples
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|file| {
/// file.try_clone()
/// .map(|(file, clone)| {
/// // do something with the file and the clone
/// # println!("{:?} {:?}", file, clone);
/// })
/// .map_err(|(file, err)| {
/// // you get the original file back if there's an error
/// # println!("{:?}", file);
/// err
/// })
/// })
/// .map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn try_clone(self) -> CloneFuture {
CloneFuture::new(self)
}
/// Changes the permissions on the underlying file.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `fchmod` function on Unix and
/// the `SetFileInformationByHandle` function on Windows. Note that, this
/// [may change in the future][changes].
///
/// [changes]: https://doc.rust-lang.org/std/io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error if the user lacks permission change
/// attributes on the underlying file. It may also return an error in other
/// os-specific unspecified cases.
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|file| file.metadata())
/// .map(|(mut file, metadata)| {
/// let mut perms = metadata.permissions();
/// perms.set_readonly(true);
/// match file.poll_set_permissions(perms) {
/// Err(e) => eprintln!("{}", e),
/// _ => println!("permissions set!"),
/// }
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn poll_set_permissions(&mut self, perm: Permissions) -> Poll<(), io::Error> {
::blocking_io(|| self.std().set_permissions(perm))
}
/// Destructures the `tokio_fs::File` into a [`std::fs::File`][std].
///
/// # Panics
///
/// This function will panic if `shutdown` has been called.
///
/// [std]: https://doc.rust-lang.org/std/fs/struct.File.html
///
/// # Examples
///
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .map(|file| {
/// let std_file = file.into_std();
/// // do something with the std::fs::File
/// # println!("{:?}", std_file);
/// }).map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn into_std(mut self) -> StdFile {
self.std.take().expect("`File` instance already shutdown")
}
fn std(&mut self) -> &mut StdFile {
self.std.as_mut().expect("`File` instance already shutdown")
}
}
impl Read for File {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
::would_block(|| self.std().read(buf))
}
}
impl AsyncRead for File {
unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
false
}
}
impl Write for File {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
::would_block(|| self.std().write(buf))
}
fn flush(&mut self) -> io::Result<()> {
::would_block(|| self.std().flush())
}
}
impl AsyncWrite for File {
fn shutdown(&mut self) -> Poll<(), io::Error> {
::blocking_io(|| {
self.std = None;
Ok(())
})
}
}
impl Drop for File {
fn drop(&mut self) {
if let Some(_std) = self.std.take() {
// This is probably fine as closing a file *shouldn't* be a blocking
// operation. That said, ideally `shutdown` is called first.
}
}
}
+38
View File
@@ -0,0 +1,38 @@
use super::File;
use futures::{Future, Poll};
use std::fs::OpenOptions as StdOpenOptions;
use std::io;
use std::path::Path;
/// Future returned by `File::open` and resolves to a `File` instance.
#[derive(Debug)]
pub struct OpenFuture<P> {
options: StdOpenOptions,
path: P,
}
impl<P> OpenFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
pub(crate) fn new(options: StdOpenOptions, path: P) -> Self {
OpenFuture { options, path }
}
}
impl<P> Future for OpenFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
type Item = File;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let std = try_ready!(::blocking_io(|| self.options.open(&self.path)));
let file = File::from_std(std);
Ok(file.into())
}
}
+104
View File
@@ -0,0 +1,104 @@
use super::OpenFuture;
use std::convert::From;
use std::fs::OpenOptions as StdOpenOptions;
use std::path::Path;
/// Options and flags which can be used to configure how a file is opened.
///
/// This is a specialized version of [`std::fs::OpenOptions`] for usage from
/// the Tokio runtime.
///
/// `From<std::fs::OpenOptions>` is implemented for more advanced configuration
/// than the methods provided here.
///
/// [`std::fs::OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
#[derive(Clone, Debug)]
pub struct OpenOptions(StdOpenOptions);
impl OpenOptions {
/// Creates a blank new set of options ready for configuration.
///
/// All options are initially set to `false`.
///
/// # Examples
///
/// ```ignore
/// use tokio::fs::OpenOptions;
///
/// let mut options = OpenOptions::new();
/// let future = options.read(true).open("foo.txt");
/// ```
pub fn new() -> OpenOptions {
OpenOptions(StdOpenOptions::new())
}
/// See the underlying [`read`] call for details.
///
/// [`read`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.read
pub fn read(&mut self, read: bool) -> &mut OpenOptions {
self.0.read(read);
self
}
/// See the underlying [`write`] call for details.
///
/// [`write`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.write
pub fn write(&mut self, write: bool) -> &mut OpenOptions {
self.0.write(write);
self
}
/// See the underlying [`append`] call for details.
///
/// [`append`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.append
pub fn append(&mut self, append: bool) -> &mut OpenOptions {
self.0.append(append);
self
}
/// See the underlying [`truncate`] call for details.
///
/// [`truncate`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.truncate
pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
self.0.truncate(truncate);
self
}
/// See the underlying [`create`] call for details.
///
/// [`create`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create
pub fn create(&mut self, create: bool) -> &mut OpenOptions {
self.0.create(create);
self
}
/// See the underlying [`create_new`] call for details.
///
/// [`create_new`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create_new
pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
self.0.create_new(create_new);
self
}
/// Opens a file at `path` with the options specified by `self`.
///
/// # Errors
///
/// `OpenOptionsFuture` results in an error if called from outside of the
/// Tokio runtime or if the underlying [`open`] call results in an error.
///
/// [`open`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open
pub fn open<P>(&self, path: P) -> OpenFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
OpenFuture::new(self.0.clone(), path)
}
}
impl From<StdOpenOptions> for OpenOptions {
fn from(options: StdOpenOptions) -> OpenOptions {
OpenOptions(options)
}
}
+36
View File
@@ -0,0 +1,36 @@
use super::File;
use futures::{Future, Poll};
use std::io;
/// Future returned by `File::seek`.
#[derive(Debug)]
pub struct SeekFuture {
inner: Option<File>,
pos: io::SeekFrom,
}
impl SeekFuture {
pub(crate) fn new(file: File, pos: io::SeekFrom) -> Self {
Self {
pos,
inner: Some(file),
}
}
}
impl Future for SeekFuture {
type Item = (File, u64);
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let pos = try_ready!(self
.inner
.as_mut()
.expect("Cannot poll `SeekFuture` after it resolves")
.poll_seek(self.pos));
let inner = self.inner.take().unwrap();
Ok((inner, pos).into())
}
}
+51
View File
@@ -0,0 +1,51 @@
use std::fs;
use std::io;
use std::path::Path;
use futures::{Future, Poll};
/// Creates a new hard link on the filesystem.
///
/// The `dst` path will be a link pointing to the `src` path. Note that systems
/// often require these two paths to both be located on the same filesystem.
///
/// This is an async version of [`std::fs::hard_link`][std]
///
/// [std]: https://doc.rust-lang.org/std/fs/fn.hard_link.html
pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> HardLinkFuture<P, Q> {
HardLinkFuture::new(src, dst)
}
/// Future returned by `hard_link`.
#[derive(Debug)]
pub struct HardLinkFuture<P, Q>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
src: P,
dst: Q,
}
impl<P, Q> HardLinkFuture<P, Q>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
fn new(src: P, dst: Q) -> HardLinkFuture<P, Q> {
HardLinkFuture { src: src, dst: dst }
}
}
impl<P, Q> Future for HardLinkFuture<P, Q>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
::blocking_io(|| fs::hard_link(&self.src, &self.dst))
}
}
+113
View File
@@ -0,0 +1,113 @@
#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-fs/0.1.7")]
//! Asynchronous file and standard stream adaptation.
//!
//! This module contains utility methods and adapter types for input/output to
//! files or standard streams (`Stdin`, `Stdout`, `Stderr`), and
//! filesystem manipulation, for use within (and only within) a Tokio runtime.
//!
//! Tasks run by *worker* threads should not block, as this could delay
//! servicing reactor events. Portable filesystem operations are blocking,
//! however. This module offers adapters which use a [`blocking`] annotation
//! to inform the runtime that a blocking operation is required. When
//! necessary, this allows the runtime to convert the current thread from a
//! *worker* to a *backup* thread, where blocking is acceptable.
//!
//! ## Usage
//!
//! Where possible, users should prefer the provided asynchronous-specific
//! traits such as [`AsyncRead`], or methods returning a `Future` or `Poll`
//! type. Adaptions also extend to traits like `std::io::Read` where methods
//! return `std::io::Result`. Be warned that these adapted methods may return
//! `std::io::ErrorKind::WouldBlock` if a *worker* thread can not be converted
//! to a *backup* thread immediately. See [tokio-threadpool] for more details
//! of the threading model and [`blocking`].
//!
//! [`blocking`]: https://docs.rs/tokio-threadpool/0.1/tokio_threadpool/fn.blocking.html
//! [`AsyncRead`]: https://docs.rs/tokio-io/0.1/tokio_io/trait.AsyncRead.html
//! [tokio-threadpool]: https://docs.rs/tokio-threadpool/0.1/tokio_threadpool
#[macro_use]
extern crate futures;
extern crate tokio_io;
extern crate tokio_threadpool;
mod create_dir;
mod create_dir_all;
pub mod file;
mod hard_link;
mod metadata;
pub mod os;
mod read;
mod read_dir;
mod read_link;
mod remove_dir;
mod remove_file;
mod rename;
mod set_permissions;
mod stderr;
mod stdin;
mod stdout;
mod symlink_metadata;
mod write;
pub use create_dir::{create_dir, CreateDirFuture};
pub use create_dir_all::{create_dir_all, CreateDirAllFuture};
pub use file::File;
pub use file::OpenOptions;
pub use hard_link::{hard_link, HardLinkFuture};
pub use metadata::{metadata, MetadataFuture};
pub use read::{read, ReadFile};
pub use read_dir::{read_dir, DirEntry, ReadDir, ReadDirFuture};
pub use read_link::{read_link, ReadLinkFuture};
pub use remove_dir::{remove_dir, RemoveDirFuture};
pub use remove_file::{remove_file, RemoveFileFuture};
pub use rename::{rename, RenameFuture};
pub use set_permissions::{set_permissions, SetPermissionsFuture};
pub use stderr::{stderr, Stderr};
pub use stdin::{stdin, Stdin};
pub use stdout::{stdout, Stdout};
pub use symlink_metadata::{symlink_metadata, SymlinkMetadataFuture};
pub use write::{write, WriteFile};
use futures::Async::*;
use futures::Poll;
use std::io;
use std::io::ErrorKind::{Other, WouldBlock};
fn blocking_io<F, T>(f: F) -> Poll<T, io::Error>
where
F: FnOnce() -> io::Result<T>,
{
match tokio_threadpool::blocking(f) {
Ok(Ready(Ok(v))) => Ok(v.into()),
Ok(Ready(Err(err))) => Err(err),
Ok(NotReady) => Ok(NotReady),
Err(_) => Err(blocking_err()),
}
}
fn would_block<F, T>(f: F) -> io::Result<T>
where
F: FnOnce() -> io::Result<T>,
{
match tokio_threadpool::blocking(f) {
Ok(Ready(Ok(v))) => Ok(v),
Ok(Ready(Err(err))) => {
debug_assert_ne!(err.kind(), WouldBlock);
Err(err)
}
Ok(NotReady) => Err(WouldBlock.into()),
Err(_) => Err(blocking_err()),
}
}
fn blocking_err() -> io::Error {
io::Error::new(
Other,
"`blocking` annotated I/O must be called \
from the context of the Tokio runtime.",
)
}
+45
View File
@@ -0,0 +1,45 @@
use super::blocking_io;
use futures::{Future, Poll};
use std::fs::{self, Metadata};
use std::io;
use std::path::Path;
/// Queries the file system metadata for a path.
pub fn metadata<P>(path: P) -> MetadataFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
MetadataFuture::new(path)
}
/// Future returned by `metadata`.
#[derive(Debug)]
pub struct MetadataFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
path: P,
}
impl<P> MetadataFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
pub(crate) fn new(path: P) -> Self {
Self { path }
}
}
impl<P> Future for MetadataFuture<P>
where
P: AsRef<Path> + Send + 'static,
{
type Item = Metadata;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
blocking_io(|| fs::metadata(&self.path))
}
}
+6
View File
@@ -0,0 +1,6 @@
//! OS-specific functionality.
#[cfg(unix)]
pub mod unix;
#[cfg(windows)]
pub mod windows;
+52
View File
@@ -0,0 +1,52 @@
//! Unix-specific extensions to primitives in the `tokio_fs` module.
use std::io;
use std::os::unix::fs;
use std::path::Path;
use futures::{Future, Poll};
/// Creates a new symbolic link on the filesystem.
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
/// This is an async version of [`std::os::unix::fs::symlink`][std]
///
/// [std]: https://doc.rust-lang.org/std/os/unix/fs/fn.symlink.html
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> SymlinkFuture<P, Q> {
SymlinkFuture::new(src, dst)
}
/// Future returned by `symlink`.
#[derive(Debug)]
pub struct SymlinkFuture<P, Q>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
src: P,
dst: Q,
}
impl<P, Q> SymlinkFuture<P, Q>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
fn new(src: P, dst: Q) -> SymlinkFuture<P, Q> {
SymlinkFuture { src: src, dst: dst }
}
}
impl<P, Q> Future for SymlinkFuture<P, Q>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
::blocking_io(|| fs::symlink(&self.src, &self.dst))
}
}
+7
View File
@@ -0,0 +1,7 @@
//! Windows-specific extensions for the primitives in the `tokio_fs` module.
mod symlink_dir;
mod symlink_file;
pub use self::symlink_dir::{symlink_dir, SymlinkDirFuture};
pub use self::symlink_file::{symlink_file, SymlinkFileFuture};
+51
View File
@@ -0,0 +1,51 @@
use std::io;
use std::os::windows::fs;
use std::path::Path;
use futures::{Future, Poll};
/// Creates a new directory symlink on the filesystem.
///
/// The `dst` path will be a directory symbolic link pointing to the `src`
/// path.
///
/// This is an async version of [`std::os::windows::fs::symlink_dir`][std]
///
/// [std]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_dir.html
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> SymlinkDirFuture<P, Q> {
SymlinkDirFuture::new(src, dst)
}
/// Future returned by `symlink_dir`.
#[derive(Debug)]
pub struct SymlinkDirFuture<P, Q>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
src: P,
dst: Q,
}
impl<P, Q> SymlinkDirFuture<P, Q>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
fn new(src: P, dst: Q) -> SymlinkDirFuture<P, Q> {
SymlinkDirFuture { src: src, dst: dst }
}
}
impl<P, Q> Future for SymlinkDirFuture<P, Q>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
::blocking_io(|| fs::symlink_dir(&self.src, &self.dst))
}
}

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