Skip to content

Commit

Permalink
Merge pull request stlab#362 from stlab/develop
Browse files Browse the repository at this point in the history
1.6.0 release
  • Loading branch information
FelixPetriconi authored Feb 9, 2021
2 parents c9d5de0 + 314193c commit 8bec449
Show file tree
Hide file tree
Showing 31 changed files with 649 additions and 438 deletions.
3 changes: 2 additions & 1 deletion .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ build_script:
- cd build
- cmake -G "%CMAKE_TOOLSET%" -D BOOST_ROOT="%BOOST_ROOT%" -D Boost_USE_STATIC_LIBS=ON ..
- cmake --build . --config Release
- ctest -C Release
- set TESTS_ARGUMENTS=--log_level=message
- ctest -C Release --verbose --no-compress-output
3 changes: 2 additions & 1 deletion .travis/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ if [ $? -ne 0 ]; then exit 1; fi

if $coverage; then lcov -c -i -b .. -d . -o Coverage.baseline; fi

ctest --output-on-failure -j$NPROC
export TESTS_ARGUMENTS=--log_level=message
ctest -C Release -j$NPROC --verbose --no-compress-output
if [ $? -ne 0 ]; then exit 1; fi

if $coverage; then
Expand Down
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## v1.6.0 - 2021 - February 9
- Backport the library to support C++14 and later
- Better auto-configuration - no need for compiler flags.
- Supported for threaded wasm using the portable tasking system (auto-configured).

## v1.5.6 - 2021 - February 1
- Fixed issues
= [#352]:(https://github.com/stlab/libraries/issues/352) Non portable 'warning' preprocessor command
Expand Down
15 changes: 11 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ endif()

project( stlab VERSION 1.5.6 LANGUAGES CXX )

set(CMAKE_CXX_STANDARD 17)
# Overriden from Conan?
# set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include( CTest )
Expand All @@ -40,7 +41,7 @@ option( stlab.boost_variant "Prefer Boost::variant to std::variant" OFF )
option( stlab.boost_optional "Prefer Boost::optional to std::optional" OFF )
option( stlab.coroutines "Leverage the coroutine TS in stlab" OFF )

set(stlab.task_system "portable" CACHE STRING "Select the task system (portable|libdispatch|emscripten|pnacl|windows).")
set(stlab.task_system "header" CACHE STRING "Select the task system (header|portable|libdispatch|emscripten|pnacl|windows).")

#
# On apple we have to force the usage of boost.variant, because Apple's
Expand All @@ -67,7 +68,7 @@ add_library( stlab::stlab ALIAS stlab )
# features ensures that the corresponding C++ standard flag is populated in
# targets linking to stlab.
#
target_compile_features( stlab INTERFACE cxx_std_17 )
# target_compile_features( stlab INTERFACE cxx_std_14)

#
# The include directory for stlab can be expected to vary between build
Expand Down Expand Up @@ -106,6 +107,9 @@ if( EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
# conanfile.txt
#
conan_basic_setup( TARGETS KEEP_RPATHS )

# REVISIT (sparent) : This should not be necessary but appears to be
set(CMAKE_CXX_STANDARD ${CONAN_SETTINGS_COMPILER_CPPSTD})
endif()

if ( stlab.testing OR stlab.boost_variant OR stlab.boost_optional )
Expand Down Expand Up @@ -168,7 +172,10 @@ if (NOT APPLE AND (${stlab.task_system} STREQUAL "libdispatch"))
target_link_libraries(${CMAKE_PROJECT_NAME} INTERFACE libdispatch::libdispatch)
endif()

if (${stlab.task_system} STREQUAL "portable")
if (${stlab.task_system} STREQUAL "header")
# Task System is selected in concurrency/config_task_system.hpp
# Nothing to define.
elseif (${stlab.task_system} STREQUAL "portable")
target_compile_definitions( stlab INTERFACE -DSTLAB_FORCE_TASK_SYSTEM_PORTABLE )
elseif (${stlab.task_system} STREQUAL "libdispatch")
target_compile_definitions( stlab INTERFACE -DSTLAB_FORCE_TASK_SYSTEM_LIBDISPATCH )
Expand Down
6 changes: 6 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
filtered_builds = []
for settings, options, env_vars, build_requires, reference in builder.items:

#TODO(fernando): auto and portable Task Systems are disabled until we fix the deadlock
# using portable in Windows.
# opts_auto = copy.deepcopy(options)
# opts_auto["stlab:task_system"] = "auto"
# filtered_builds.append([settings, opts_auto, env_vars, build_requires, reference])

if settings["compiler"] == "clang":
opts_libdispatch = copy.deepcopy(options)
opts_libdispatch["stlab:task_system"] = "libdispatch"
Expand Down
7 changes: 7 additions & 0 deletions cmake/RunTests.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
if(NOT DEFINED ENV{TESTS_ARGUMENTS})
set(ENV{TESTS_ARGUMENTS} "")
endif()
execute_process(COMMAND ${TEST_EXECUTABLE} $ENV{TESTS_ARGUMENTS} RESULT_VARIABLE result)
if(NOT "${result}" STREQUAL "0")
message(FATAL_ERROR "Test failed with return value '${result}'")
endif()
12 changes: 7 additions & 5 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class StlabLibrariesConan(ConanFile):
"boost_optional": [True, False],
"boost_variant": [True, False],
"coroutines": [True, False],
"task_system": ["portable", "libdispatch", "emscripten", "pnacl", "windows", "auto"],
"task_system": ["header", "portable", "libdispatch", "emscripten", "pnacl", "windows", "auto"],
}

default_options = {
Expand All @@ -37,7 +37,7 @@ class StlabLibrariesConan(ConanFile):
"boost_optional": False,
"boost_variant": False,
"coroutines": False,
"task_system": "auto",
"task_system": "header",
}

def _log(self, str):
Expand Down Expand Up @@ -109,7 +109,8 @@ def _configure_boost(self):
def _fix_boost_components(self):
if self.settings.os != "Macos": return
if self.settings.compiler != "apple-clang": return
if float(str(self.settings.compiler.version)) >= 12: return

if (float(str(self.settings.compiler.version)) >= 12) and not ((self.settings.compiler.cppstd == "14") or (self.settings.compiler.cppstd == "gnu14")): return

#
# On Apple we have to force the usage of boost.variant, because Apple's implementation of C++17 is not complete.
Expand Down Expand Up @@ -171,6 +172,8 @@ def _configure_task_system(self):
def configure(self):
ConanFile.configure(self)

tools.check_min_cppstd(self, "14")

self._fix_boost_components()

if self._use_boost():
Expand All @@ -195,11 +198,10 @@ def build(self):
cmake.configure()
cmake.build()
cmake.test(output_on_failure=True)

def package(self):
self.copy("*.hpp")

def imports(self):
self.copy("*.dll", "./bin", "bin")
self.copy("*.dylib", "./bin", "lib")

2 changes: 1 addition & 1 deletion setup_xcode.sh → setup_xcode_cpp14.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
mkdir -p build
pushd build

conan install .. --build=missing -s build_type=Debug
conan install .. --build=missing -s build_type=Debug -o testing=True -s compiler.cppstd=14

cmake -GXcode -D CMAKE_BUILD_TYPE=debug -D stlab_testing=ON ..

Expand Down
10 changes: 10 additions & 0 deletions setup_xcode_cpp17.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

mkdir -p build
pushd build

conan install .. --build=missing -s build_type=Debug -o testing=True -s compiler.cppstd=17

cmake -GXcode -D CMAKE_BUILD_TYPE=debug -D stlab_testing=ON ..

popd
136 changes: 115 additions & 21 deletions stlab/concurrency/channel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,21 @@ struct invoke_variant_dispatcher {
template <>
struct invoke_variant_dispatcher<1> {
template <typename F, typename T, typename Arg>
static auto invoke_(F&& f, T& t) {
if constexpr (std::is_same<Arg, void>::value) {
return;
} else if constexpr (std::is_same<Arg, detail::avoid_>::value) {
return std::forward<F>(f)();
} else {
return std::forward<F>(f)(std::move(stlab::get<Arg>(std::get<0>(t))));
}
static auto invoke_(F&&, T&) -> std::enable_if_t<std::is_same<Arg, void>::value, void> {
return;
}
template <typename F, typename T, typename Arg>
static auto invoke_(F&& f, T&) -> std::enable_if_t<std::is_same<Arg, detail::avoid_>::value,
decltype(std::forward<F>(f)())> {
return std::forward<F>(f)();
}
template <typename F, typename T, typename Arg>
static auto invoke_(F&& f, T& t) -> std::enable_if_t<
!(std::is_same<Arg, detail::avoid_>::value || std::is_same<Arg, detail::avoid_>::value),
decltype(std::forward<F>(f)(std::move(stlab::get<Arg>(std::get<0>(t)))))> {
return std::forward<F>(f)(std::move(stlab::get<Arg>(std::get<0>(t))));
}

template <typename F, typename T, typename... Args>
static auto invoke(F&& f, T& t) {
return invoke_<F, T, first_t<Args...>>(std::forward<F>(f), t);
Expand Down Expand Up @@ -699,7 +705,7 @@ struct downstream<
_data = std::forward<F>(f);
}

void clear() { _data = nullopt; }
void clear() { _data = stlab::nullopt; }

std::size_t size() const { return 1; }

Expand Down Expand Up @@ -828,7 +834,7 @@ struct shared_process
if (do_final) {
std::unique_lock<std::mutex> lock(_downstream_mutex);
_downstream.clear(); // This will propagate the close to anything downstream
_process = nullopt;
_process = stlab::nullopt;
}
}

Expand Down Expand Up @@ -910,8 +916,14 @@ struct shared_process
return bool(message);
}

/*
REVISIT (sparent) : Next two cases are nearly identical, complicated by the need to
remove constexpr if to support C++14.
*/

template <typename U>
auto step() -> std::enable_if_t<has_process_yield_v<unwrap_reference_t<U>>> {
auto step() -> std::enable_if_t<has_process_yield_v<unwrap_reference_t<U>> &&
!has_process_await_v<unwrap_reference_t<T>, Args...>> {
// in case that the timeout function is just been executed then we have to re-schedule
// the current run
lock_t lock(_timeout_function_control, std::try_to_lock);
Expand All @@ -926,12 +938,90 @@ struct shared_process
is done on yield()
*/
try {
if constexpr (has_process_await_v<unwrap_reference_t<T>, Args...>) {
while (get_process_state(_process).first == process_state::await) {
if (!dequeue()) break;
}
if (get_process_state(_process).first == process_state::await) return;

// Workaround until we can use structured bindings
auto tmp = get_process_state(_process);
const auto& state = tmp.first;
const auto& duration = tmp.second;

/*
Once we hit yield, go ahead and call it. If the yield is delayed then schedule it.
This process will be considered running until it executes.
*/
if (state == process_state::yield) {
if (std::chrono::duration_cast<std::chrono::nanoseconds>(duration) <=
std::chrono::nanoseconds::min())
broadcast(unwrap(*_process).yield());
else
execute_at(duration,
_executor)([_weak_this = make_weak_ptr(this->shared_from_this())] {
auto _this = _weak_this.lock();
if (!_this) return;
_this->try_broadcast();
});
}

/*
We are in an await state and the queue is empty.
If we await forever then task_done() leaving us in an await state.
else if we await with an expired timeout then go ahead and yield now.
else schedule a timeout when we will yield if not canceled by intervening await.
*/
else if (std::chrono::duration_cast<std::chrono::nanoseconds>(duration) ==
std::chrono::nanoseconds::max()) {
task_done();
} else if (std::chrono::duration_cast<std::chrono::nanoseconds>(duration) <=
std::chrono::nanoseconds::min()) {
broadcast(unwrap(*_process).yield());
} else {
if (get_process_state(_process).first == process_state::await) return;
/* Schedule a timeout. */
_timeout_function_active = true;
execute_at(duration,
_executor)([_weak_this = make_weak_ptr(this->shared_from_this())] {
auto _this = _weak_this.lock();
// It may be that the complete channel is gone in the meanwhile
if (!_this) return;

// try_lock can fail spuriously
while (true) {
lock_t lock(_this->_timeout_function_control, std::try_to_lock);
if (!lock) continue;

// we were cancelled
if (get_process_state(_this->_process).first != process_state::yield) {
_this->try_broadcast();
_this->_timeout_function_active = false;
}
return;
}
});
}
} catch (...) { // this catches exceptions during _process.await() and _process.yield()
broadcast(std::move(std::current_exception()));
}
}

template <typename U>
auto step() -> std::enable_if_t<has_process_yield_v<unwrap_reference_t<U>> &&
has_process_await_v<unwrap_reference_t<T>, Args...>> {
// in case that the timeout function is just been executed then we have to re-schedule
// the current run
lock_t lock(_timeout_function_control, std::try_to_lock);
if (!lock) {
run();
return;
}
_timeout_function_active = false;

/*
While we are waiting we will flush the queue. The assumption here is that work
is done on yield()
*/
try {
while (get_process_state(_process).first == process_state::await) {
if (!dequeue()) break;
}

// Workaround until we can use structured bindings
Expand All @@ -944,7 +1034,8 @@ struct shared_process
This process will be considered running until it executes.
*/
if (state == process_state::yield) {
if (std::chrono::duration_cast<std::chrono::nanoseconds>(duration) <= std::chrono::nanoseconds::min())
if (std::chrono::duration_cast<std::chrono::nanoseconds>(duration) <=
std::chrono::nanoseconds::min())
broadcast(unwrap(*_process).yield());
else
execute_at(duration,
Expand All @@ -962,14 +1053,17 @@ struct shared_process
else if we await with an expired timeout then go ahead and yield now.
else schedule a timeout when we will yield if not canceled by intervening await.
*/
else if (std::chrono::duration_cast<std::chrono::nanoseconds>(duration) == std::chrono::nanoseconds::max()) {
else if (std::chrono::duration_cast<std::chrono::nanoseconds>(duration) ==
std::chrono::nanoseconds::max()) {
task_done();
} else if (std::chrono::duration_cast<std::chrono::nanoseconds>(duration) <= std::chrono::nanoseconds::min()) {
} else if (std::chrono::duration_cast<std::chrono::nanoseconds>(duration) <=
std::chrono::nanoseconds::min()) {
broadcast(unwrap(*_process).yield());
} else {
/* Schedule a timeout. */
_timeout_function_active = true;
execute_at(duration, _executor)([_weak_this = make_weak_ptr(this->shared_from_this())] {
execute_at(duration,
_executor)([_weak_this = make_weak_ptr(this->shared_from_this())] {
auto _this = _weak_this.lock();
// It may be that the complete channel is gone in the meanwhile
if (!_this) return;
Expand Down Expand Up @@ -1367,7 +1461,7 @@ detail::annotated_process<F> operator&(detail::annotated_process<F>&& a, buffer_
/**************************************************************************************************/

template <typename T>
class [[nodiscard]] receiver {
class STLAB_NODISCARD() receiver {
using ptr_t = std::shared_ptr<detail::shared_process_receiver<T>>;

ptr_t _p;
Expand Down
9 changes: 9 additions & 0 deletions stlab/concurrency/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@
#endif
#endif

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

#if __cplusplus < 201703L
#define STLAB_NODISCARD()
#else
#define STLAB_NODISCARD() [[nodiscard]]
#endif


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

#endif // STLAB_CONCURRENCY_CONFIG_HPP
Expand Down
Loading

0 comments on commit 8bec449

Please sign in to comment.