Skip to content

Commit d1016a8

Browse files
authored
Minor fixes to await and await docs. (#555)
* Improved docs for await and related operations * Improved implementation of await * Fixed several test cases for invoke_waiting.
1 parent d80dacd commit d1016a8

File tree

10 files changed

+95
-135
lines changed

10 files changed

+95
-135
lines changed

CMakePresets.json

+26-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@
2121
"stlab.coverage": "OFF"
2222
}
2323
},
24+
{
25+
"name": "debug-cpp20-tsan-ubsan-portable",
26+
"description": "Ninja Debug Build",
27+
"hidden": false,
28+
"generator": "Ninja",
29+
"binaryDir": "${sourceDir}/build/ninja-cpp20-debug-thread-undefined",
30+
"cacheVariables": {
31+
"CMAKE_CXX_STANDARD": "20",
32+
"CMAKE_BUILD_TYPE": "DEBUG",
33+
"STLAB_TASK_SYSTEM": "portable",
34+
"CMAKE_CXX_FLAGS": "-fsanitize=thread -fsanitize=undefined"
35+
}
36+
},
2437
{
2538
"name": "ninja-cpp20-debug-thread-undefined",
2639
"description": "Ninja Debug Build",
@@ -30,8 +43,7 @@
3043
"cacheVariables": {
3144
"CMAKE_CXX_STANDARD": "20",
3245
"CMAKE_BUILD_TYPE": "DEBUG",
33-
"CMAKE_CXX_FLAGS": "-fsanitize=thread -fsanitize=undefined",
34-
"CMAKE_LINKER_FLAGS": "-fsanitize=thread -fsanitize=undefined"
46+
"CMAKE_CXX_FLAGS": "-fsanitize=thread -fsanitize=undefined"
3547
}
3648
},
3749
{
@@ -45,6 +57,18 @@
4557
"CMAKE_BUILD_TYPE": "DEBUG"
4658
}
4759
},
60+
{
61+
"name": "xcode-cpp20-debug-portable",
62+
"description": "",
63+
"hidden": false,
64+
"generator": "Xcode",
65+
"binaryDir": "${sourceDir}/build/xcode-cpp20-debug-portable",
66+
"cacheVariables": {
67+
"CMAKE_CXX_STANDARD": "20",
68+
"CMAKE_BUILD_TYPE": "DEBUG",
69+
"STLAB_TASK_SYSTEM": "portable"
70+
}
71+
},
4872
{
4973
"name": "ninja-cpp17-debug",
5074
"description": "Ninja Debug Build",

docs/README.md

+6-44
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,15 @@
11
# `stlab` Documentation
22

3-
Pull requests for typos, examples, and other improvements are welcome. To file an issue, please use the [libraries repository](https://github.com/stlab/libraries).
4-
5-
# Branch states
6-
7-
\[ These are from the old site - FIX ME \]
8-
9-
- **`master`:** [![master build](https://travis-ci.org/stlab/stlab.github.io.svg?branch=master)](https://travis-ci.org/stlab/stlab.github.io) [![master coverage](https://codecov.io/github/stlab/stlab.github.io/coverage.svg?branch=master)](https://codecov.io/gh/stlab/stlab.github.io/branch/master)
10-
11-
- **`develop`:** [![develop build](https://travis-ci.org/stlab/stlab.github.io.svg?branch=develop)](https://travis-ci.org/stlab/stlab.github.io)
12-
[![develop coverage](https://codecov.io/github/stlab/stlab.github.io/coverage.svg?branch=develop)](https://codecov.io/gh/stlab/stlab.github.io/branch/develop)
13-
14-
# Building (Mac)
15-
16-
You'll need Homebrew to make sure you have the most recent version of Ruby.
17-
18-
## Setup
19-
20-
1. Clone the repo
21-
2. `brew install ruby`
22-
3. `sudo gem install bundle jekyll github-pages liquid`
23-
24-
Periodically run `gem update` and `bundle update` to make sure you have the latest jekyll tooling.
25-
26-
## Building Docs
3+
This site is available at [stlab.cc](https://stlab.cc).
274

28-
```
29-
cd ./docs
30-
bundle exec jekyll serve --watch
31-
```
32-
33-
Documentation viewable at `localhost:4000`
34-
Modifying sources should auto-regenerate the documentation
5+
Pull requests for typos, examples, and other improvements are welcome. To file an issue, please use the [libraries repository](https://github.com/stlab/libraries).
356

36-
## Building Examples
7+
## Building the Documentation
378

38-
1. `./build.sh` will download dependencies, build, and run all the `*.cpp` files in the `libraries` directory.
9+
To run a local Jekyll server, see the instructions in the docker-tools [README](../tools/docker-tools/README.md).
3910

4011
## Running Hyde in Docker
4112

42-
The following directory structure is assumed.
43-
44-
[ The longer term plan is to migrate the docs for the libraries into the library repo. We also need a plan for the structure of the build directory, a]
45-
46-
```
47-
. # This directory stlab.github.io
48-
../libraries # The stlab/libraries repo
49-
../builds/hyde # The cmake build directory configures for building docs
50-
```
51-
5213
Configure the build as follows:
5314

5415
```
@@ -81,5 +42,6 @@ cd /mnt/host/libraries/docs
8142
```
8243

8344
\[ this is from the old docs - need to update the docs and script.
45+
8446
> (or, simply `-u`) to generate the boilerplate for it. Then, fill in any fields marked as `__MISSING__`. Fields marked as `__OPTIONAL__` may be omitted.
85-
\]
47+
> \]

docs/include/stlab/algorithm/reverse.hpp/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ layout: library
33
title: stlab/algorithm/reverse.hpp
44
hyde:
55
owner: sean-parent
6-
brief: __MISSING__
6+
brief: A collection of algorithms for reversing sequences.
77
tags:
88
- sourcefile
99
library-type: sourcefile

docs/include/stlab/concurrency/await.hpp/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ layout: library
33
title: stlab/concurrency/await.hpp
44
hyde:
55
owner: sean-parent
6-
brief: "Await provides utilities to synchronously await the value from a `future` and to notify the default executor that a task is waiting. Blocking calls are discouraged because they may lead to deadlocks or thread explosions.\n\nThere is a good presentation of the issues [here](https://youtu.be/Z86b3Rd09sE).\n"
6+
brief: "Await provides utilities to await the value from a `future<>` synchronously and to notify the default executor that a task is waiting. Blocking calls are discouraged because they may lead to deadlocks or thread explosions.\n\nThere is a good presentation of the issues [here](https://youtu.be/Z86b3Rd09sE).\n"
77
tags:
88
- sourcefile
99
library-type: sourcefile

docs/tools/docker-tools/Dockerfile

+17-32
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ FROM ubuntu:latest
55

66
ARG DEBIAN_FRONTEND=noninteractive
77
RUN apt-get update && apt-get install -y \
8-
apt-utils \
9-
fswatch \
10-
g++ \
11-
git \
12-
libreadline-dev \
13-
make \
14-
nodejs \
15-
npm \
16-
rbenv \
17-
wget \
18-
zlib1g-dev
8+
apt-utils \
9+
fswatch \
10+
g++ \
11+
git \
12+
libreadline-dev \
13+
make \
14+
nodejs \
15+
npm \
16+
rbenv \
17+
wget \
18+
zlib1g-dev
1919

2020
RUN apt-get install -y libyaml-dev
2121

@@ -26,9 +26,6 @@ RUN export N_USE_XZ=0; n latest
2626
RUN npm install -g npm@latest
2727
RUN npm install -g browser-sync
2828

29-
###### Temporary #####
30-
RUN npm install -g sass-migrator
31-
3229
# Create a user "app" so everything is not running at root
3330
RUN useradd -ms /bin/bash app
3431
USER app
@@ -47,12 +44,12 @@ RUN git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ru
4744
# Install ruby
4845
ARG RUBY_VERSION
4946
RUN if [ -z ${RUBY_VERSION+x} ]; then \
50-
rbenv install $(rbenv install -l | grep -v - | tail -1); \
51-
rbenv global $(rbenv install -l | grep -v - | tail -1); \
52-
else \
53-
rbenv install $RUBY_VERSION; \
54-
rbenv global $RUBY_VERSION; \
55-
fi
47+
rbenv install $(rbenv install -l | grep -v - | tail -1); \
48+
rbenv global $(rbenv install -l | grep -v - | tail -1); \
49+
else \
50+
rbenv install $RUBY_VERSION; \
51+
rbenv global $RUBY_VERSION; \
52+
fi
5653

5754
# Install bundler in global ruby
5855
RUN (eval "$(rbenv init -)"; gem install bundler)
@@ -62,18 +59,6 @@ RUN (eval "$(rbenv init -)"; gem install bundler)
6259
USER app
6360
WORKDIR /home/app
6461

65-
# RUN mkdir ./install
66-
# WORKDIR ./install
67-
# COPY ./docs/Gemfile .
68-
# COPY ./docs/Gemfile.lock .
69-
# COPY ./docs/.ruby-version .
70-
71-
# RUN (eval "$(rbenv init -)"; \
72-
# bundle config set frozen true; \
73-
# bundle install)
74-
75-
# WORKDIR /home/app
76-
7762
EXPOSE 3000 3001
7863

7964
# Add version file last to avoid cache invalidation for minor releases

docs/tools/docker-tools/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Setup
44

55
### Install Docker
6+
67
If you don't already have Docker installed, [install Docker](https://docs.docker.com/get-docker/).
78

89
### Building the docker image

include/stlab/concurrency/await.hpp

+20-35
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,25 @@ inline namespace STLAB_VERSION_NAMESPACE() {
3636
/**************************************************************************************************/
3737

3838
/**
39-
Assumes f _will wait_ and wakes or adds a thread to the thread pool (to the limit) before
40-
invoking f.
39+
Assumes `f` _will wait_ and wakes or adds a thread to the thread pool (to the limit) before
40+
invoking `f`. If using a condition variable, wrap the duration of the mutex lock in `f` to avoid
41+
deadlocks.
4142
*/
4243
template <class F>
4344
auto invoke_waiting(F&& f) {
4445
#if STLAB_TASK_SYSTEM(PORTABLE)
4546
if (!detail::pts().wake()) detail::pts().add_thread();
4647
#endif
4748

48-
std::forward<F>(f)();
49+
return std::forward<F>(f)();
4950
}
5051

5152
/**************************************************************************************************/
5253

54+
/// Synchronously wait for the result `x`. If `x` resolves as an exception, the exception is
55+
/// rethrown. When using the portable task system, an additional thread is added to the pool if no
56+
/// threads are available and the maximum number of threads has not been reached.
57+
5358
template <class T>
5459
auto await(future<T>&& x) -> T {
5560
if (x.is_ready()) return std::move(x).get_ready(); // if ready, done
@@ -65,35 +70,15 @@ auto await(future<T>&& x) -> T {
6570
condition.notify_one(); // must notify under lock
6671
}
6772
});
68-
69-
#if STLAB_TASK_SYSTEM(PORTABLE)
70-
if (!detail::pts().wake()) detail::pts().add_thread();
71-
72-
/*
73-
If no tasks are available we wait for one tick of the system clock and exponentially
74-
back off on the wait as long as no tasks are available.
75-
*/
76-
77-
for (auto backoff{std::chrono::steady_clock::duration{std::chrono::milliseconds{1}}}; true;
78-
backoff *= 2) {
79-
{
80-
std::unique_lock<std::mutex> lock{m};
81-
if (condition.wait_for(lock, backoff, [&] { return result.is_ready(); })) {
82-
return std::move(result).get_ready();
83-
}
84-
}
85-
detail::pts().wake(); // try to wake something to unstick.
86-
}
87-
88-
#else
89-
90-
std::unique_lock<std::mutex> lock{m};
91-
condition.wait(lock, [&] { return result.is_ready(); });
73+
invoke_waiting([&] {
74+
std::unique_lock<std::mutex> lock{m};
75+
condition.wait(lock, [&] { return result.is_ready(); });
76+
});
9277
return std::move(result).get_ready();
93-
94-
#endif
9578
}
9679

80+
/// Equivalent to `await(copy(x))`.
81+
9782
template <class T>
9883
[[deprecated("implicit copy deprecated, use `await(std::move(f))` or `await(stlab::copy(f))`"
9984
" instead.")]]
@@ -128,8 +113,10 @@ struct blocking_get_guarded {
128113
}
129114

130115
auto wait_for(const std::chrono::nanoseconds& timeout) -> future<T> {
131-
std::unique_lock<std::mutex> lock{_mutex};
132-
_timed_out = !_condition.wait_for(lock, timeout, [&] { return _result.valid(); });
116+
_timed_out = !invoke_waiting([&] {
117+
std::unique_lock<std::mutex> lock{_mutex};
118+
return _condition.wait_for(lock, timeout, [&] { return _result.valid(); });
119+
});
133120
return _timed_out ? future<T>{} : std::move(_result);
134121
}
135122
};
@@ -140,10 +127,6 @@ template <class T>
140127
auto await_for(future<T>&& x, const std::chrono::nanoseconds& timeout) -> future<T> {
141128
if (x.is_ready()) return std::move(x);
142129

143-
#if STLAB_TASK_SYSTEM(PORTABLE)
144-
if (!detail::pts().wake()) detail::pts().add_thread();
145-
#endif
146-
147130
auto p = std::make_shared<detail::blocking_get_guarded<T>>();
148131

149132
auto hold = std::move(x).recover(immediate_executor, [_p = stlab::make_weak_ptr(p)](auto&& r) {
@@ -155,6 +138,8 @@ auto await_for(future<T>&& x, const std::chrono::nanoseconds& timeout) -> future
155138
return result.valid() ? std::move(result) : std::move(hold);
156139
}
157140

141+
/// Equivalent to `await_for(copy(x), timeout)`.
142+
158143
template <class T>
159144
[[deprecated("implicit copy deprecated, use `await_for(std::move(f), t)` or"
160145
" `await_for(stlab::copy(f), t)` instead.")]]

include/stlab/test/model.hpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <iostream>
1919
#include <mutex>
2020

21+
#include <stlab/concurrency/await.hpp>
22+
2123
/**************************************************************************************************/
2224

2325
namespace stlab {
@@ -41,9 +43,10 @@ struct annotate_counters {
4143
auto remaining() const -> std::size_t { return _copy_ctor + _move_ctor - _dtor + 1; }
4244

4345
void wait(std::size_t count) {
44-
std::unique_lock<std::mutex> lock(_mutex);
45-
while (count != remaining())
46-
_condition.wait(lock);
46+
stlab::invoke_waiting([&] {
47+
std::unique_lock<std::mutex> lock(_mutex);
48+
_condition.wait(lock, [&] { return count == remaining(); });
49+
});
4750
}
4851

4952
friend inline auto operator<<(std::ostream& out, const annotate_counters& x) -> std::ostream& {

0 commit comments

Comments
 (0)