Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor fixes to await and await docs. #555

Merged
merged 11 commits into from
Jan 25, 2025
28 changes: 26 additions & 2 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@
"stlab.coverage": "OFF"
}
},
{
"name": "debug-cpp20-tsan-ubsan-portable",
"description": "Ninja Debug Build",
"hidden": false,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/ninja-cpp20-debug-thread-undefined",
"cacheVariables": {
"CMAKE_CXX_STANDARD": "20",
"CMAKE_BUILD_TYPE": "DEBUG",
"STLAB_TASK_SYSTEM": "portable",
"CMAKE_CXX_FLAGS": "-fsanitize=thread -fsanitize=undefined"
}
},
{
"name": "ninja-cpp20-debug-thread-undefined",
"description": "Ninja Debug Build",
Expand All @@ -30,8 +43,7 @@
"cacheVariables": {
"CMAKE_CXX_STANDARD": "20",
"CMAKE_BUILD_TYPE": "DEBUG",
"CMAKE_CXX_FLAGS": "-fsanitize=thread -fsanitize=undefined",
"CMAKE_LINKER_FLAGS": "-fsanitize=thread -fsanitize=undefined"
"CMAKE_CXX_FLAGS": "-fsanitize=thread -fsanitize=undefined"
}
},
{
Expand All @@ -45,6 +57,18 @@
"CMAKE_BUILD_TYPE": "DEBUG"
}
},
{
"name": "xcode-cpp20-debug-portable",
"description": "",
"hidden": false,
"generator": "Xcode",
"binaryDir": "${sourceDir}/build/xcode-cpp20-debug-portable",
"cacheVariables": {
"CMAKE_CXX_STANDARD": "20",
"CMAKE_BUILD_TYPE": "DEBUG",
"STLAB_TASK_SYSTEM": "portable"
}
},
{
"name": "ninja-cpp17-debug",
"description": "Ninja Debug Build",
Expand Down
50 changes: 6 additions & 44 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,15 @@
# `stlab` Documentation

Pull requests for typos, examples, and other improvements are welcome. To file an issue, please use the [libraries repository](https://github.com/stlab/libraries).

# Branch states

\[ These are from the old site - FIX ME \]

- **`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)

- **`develop`:** [![develop build](https://travis-ci.org/stlab/stlab.github.io.svg?branch=develop)](https://travis-ci.org/stlab/stlab.github.io)
[![develop coverage](https://codecov.io/github/stlab/stlab.github.io/coverage.svg?branch=develop)](https://codecov.io/gh/stlab/stlab.github.io/branch/develop)

# Building (Mac)

You'll need Homebrew to make sure you have the most recent version of Ruby.

## Setup

1. Clone the repo
2. `brew install ruby`
3. `sudo gem install bundle jekyll github-pages liquid`

Periodically run `gem update` and `bundle update` to make sure you have the latest jekyll tooling.

## Building Docs
This site is available at [stlab.cc](https://stlab.cc).

```
cd ./docs
bundle exec jekyll serve --watch
```

Documentation viewable at `localhost:4000`
Modifying sources should auto-regenerate the documentation
Pull requests for typos, examples, and other improvements are welcome. To file an issue, please use the [libraries repository](https://github.com/stlab/libraries).

## Building Examples
## Building the Documentation

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

## Running Hyde in Docker

The following directory structure is assumed.

[ 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]

```
. # This directory stlab.github.io
../libraries # The stlab/libraries repo
../builds/hyde # The cmake build directory configures for building docs
```

Configure the build as follows:

```
Expand Down Expand Up @@ -81,5 +42,6 @@ cd /mnt/host/libraries/docs
```

\[ this is from the old docs - need to update the docs and script.

> (or, simply `-u`) to generate the boilerplate for it. Then, fill in any fields marked as `__MISSING__`. Fields marked as `__OPTIONAL__` may be omitted.
\]
> \]
2 changes: 1 addition & 1 deletion docs/include/stlab/algorithm/reverse.hpp/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ layout: library
title: stlab/algorithm/reverse.hpp
hyde:
owner: sean-parent
brief: __MISSING__
brief: A collection of algorithms for reversing sequences.
tags:
- sourcefile
library-type: sourcefile
Expand Down
2 changes: 1 addition & 1 deletion docs/include/stlab/concurrency/await.hpp/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ layout: library
title: stlab/concurrency/await.hpp
hyde:
owner: sean-parent
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"
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"
tags:
- sourcefile
library-type: sourcefile
Expand Down
49 changes: 17 additions & 32 deletions docs/tools/docker-tools/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ FROM ubuntu:latest

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
apt-utils \
fswatch \
g++ \
git \
libreadline-dev \
make \
nodejs \
npm \
rbenv \
wget \
zlib1g-dev
apt-utils \
fswatch \
g++ \
git \
libreadline-dev \
make \
nodejs \
npm \
rbenv \
wget \
zlib1g-dev

RUN apt-get install -y libyaml-dev

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

###### Temporary #####
RUN npm install -g sass-migrator

# Create a user "app" so everything is not running at root
RUN useradd -ms /bin/bash app
USER app
Expand All @@ -47,12 +44,12 @@ RUN git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ru
# Install ruby
ARG RUBY_VERSION
RUN if [ -z ${RUBY_VERSION+x} ]; then \
rbenv install $(rbenv install -l | grep -v - | tail -1); \
rbenv global $(rbenv install -l | grep -v - | tail -1); \
else \
rbenv install $RUBY_VERSION; \
rbenv global $RUBY_VERSION; \
fi
rbenv install $(rbenv install -l | grep -v - | tail -1); \
rbenv global $(rbenv install -l | grep -v - | tail -1); \
else \
rbenv install $RUBY_VERSION; \
rbenv global $RUBY_VERSION; \
fi

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

# RUN mkdir ./install
# WORKDIR ./install
# COPY ./docs/Gemfile .
# COPY ./docs/Gemfile.lock .
# COPY ./docs/.ruby-version .

# RUN (eval "$(rbenv init -)"; \
# bundle config set frozen true; \
# bundle install)

# WORKDIR /home/app

EXPOSE 3000 3001

# Add version file last to avoid cache invalidation for minor releases
Expand Down
1 change: 1 addition & 0 deletions docs/tools/docker-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Setup

### Install Docker

If you don't already have Docker installed, [install Docker](https://docs.docker.com/get-docker/).

### Building the docker image
Expand Down
55 changes: 20 additions & 35 deletions include/stlab/concurrency/await.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,25 @@ inline namespace STLAB_VERSION_NAMESPACE() {
/**************************************************************************************************/

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

std::forward<F>(f)();
return std::forward<F>(f)();
}

/**************************************************************************************************/

/// Synchronously wait for the result `x`. If `x` resolves as an exception, the exception is
/// rethrown. When using the portable task system, an additional thread is added to the pool if no
/// threads are available and the maximum number of threads has not been reached.

template <class T>
auto await(future<T>&& x) -> T {
if (x.is_ready()) return std::move(x).get_ready(); // if ready, done
Expand All @@ -65,35 +70,15 @@ auto await(future<T>&& x) -> T {
condition.notify_one(); // must notify under lock
}
});

#if STLAB_TASK_SYSTEM(PORTABLE)
if (!detail::pts().wake()) detail::pts().add_thread();

/*
If no tasks are available we wait for one tick of the system clock and exponentially
back off on the wait as long as no tasks are available.
*/

for (auto backoff{std::chrono::steady_clock::duration{std::chrono::milliseconds{1}}}; true;
backoff *= 2) {
{
std::unique_lock<std::mutex> lock{m};
if (condition.wait_for(lock, backoff, [&] { return result.is_ready(); })) {
return std::move(result).get_ready();
}
}
detail::pts().wake(); // try to wake something to unstick.
}

#else

std::unique_lock<std::mutex> lock{m};
condition.wait(lock, [&] { return result.is_ready(); });
invoke_waiting([&] {
std::unique_lock<std::mutex> lock{m};
condition.wait(lock, [&] { return result.is_ready(); });
});
return std::move(result).get_ready();

#endif
}

/// Equivalent to `await(copy(x))`.

template <class T>
[[deprecated("implicit copy deprecated, use `await(std::move(f))` or `await(stlab::copy(f))`"
" instead.")]]
Expand Down Expand Up @@ -128,8 +113,10 @@ struct blocking_get_guarded {
}

auto wait_for(const std::chrono::nanoseconds& timeout) -> future<T> {
std::unique_lock<std::mutex> lock{_mutex};
_timed_out = !_condition.wait_for(lock, timeout, [&] { return _result.valid(); });
_timed_out = !invoke_waiting([&] {
std::unique_lock<std::mutex> lock{_mutex};
return _condition.wait_for(lock, timeout, [&] { return _result.valid(); });
});
return _timed_out ? future<T>{} : std::move(_result);
}
};
Expand All @@ -140,10 +127,6 @@ template <class T>
auto await_for(future<T>&& x, const std::chrono::nanoseconds& timeout) -> future<T> {
if (x.is_ready()) return std::move(x);

#if STLAB_TASK_SYSTEM(PORTABLE)
if (!detail::pts().wake()) detail::pts().add_thread();
#endif

auto p = std::make_shared<detail::blocking_get_guarded<T>>();

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

/// Equivalent to `await_for(copy(x), timeout)`.

template <class T>
[[deprecated("implicit copy deprecated, use `await_for(std::move(f), t)` or"
" `await_for(stlab::copy(f), t)` instead.")]]
Expand Down
9 changes: 6 additions & 3 deletions include/stlab/test/model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <iostream>
#include <mutex>

#include <stlab/concurrency/await.hpp>

/**************************************************************************************************/

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

void wait(std::size_t count) {
std::unique_lock<std::mutex> lock(_mutex);
while (count != remaining())
_condition.wait(lock);
stlab::invoke_waiting([&] {
std::unique_lock<std::mutex> lock(_mutex);
_condition.wait(lock, [&] { return count == remaining(); });
});
}

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