On 23/10/19 12:50 -0700, Thomas Rodgers wrote:
Thomas Rodgers writes: Let's try this again.
That's better, thanks :-)
+ * include/Makefile.am: Add <stop_token> header. + * include/Makefile.in: Regenerate. + * include/std/stop_token: New file. + * include/std/version (__cpp_lib_jthread): New value. + * testsuite/30_threads/stop_token/1.cc: New test. + * testsuite/30_threads/stop_token/2.cc: New test. + * testsuite/30_threads/stop_token/stop_token.cc: New test.
ChangeLog entries should be provided separately from the patch (e.g. inline in the makefile, or as a separte attachment) because they never apply cleanly. Also it looks like you have a mixture of tabs and space there, it should be only tabs.
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index cd1e9df5482..9b4ab670315 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -416,6 +416,7 @@ std_headers = \ ${std_srcdir}/sstream \ ${std_srcdir}/stack \ ${std_srcdir}/stdexcept \ + ${std_srcdir}/stop_token \ ${std_srcdir}/streambuf \ ${std_srcdir}/string \ ${std_srcdir}/string_view \
Generated files like Makefile.in don't need to be in the patch. I use a git alias called 'filter' to filter them out: !f(){ git $@ | filterdiff -x '*/ChangeLog' -x '*/Makefile.in' -x '*/configure' -x '*/config.h.in' -x '*/doc/html/*' | sed -e '/^diff.*ChangeLog/{N;d}' ; }; f And then I create a patch with this alias: !f(){ git filter show --diff-algorithm=histogram ${*:-HEAD} > /dev/shm/patch.txt; }; f
diff --git a/libstdc++-v3/include/std/stop_token b/libstdc++-v3/include/std/stop_token new file mode 100644 index 00000000000..b3655b85eae --- /dev/null +++ b/libstdc++-v3/include/std/stop_token @@ -0,0 +1,338 @@ +// <stop_token> -*- C++ -*- + +// Copyright (C) 2008-2019 Free Software Foundation, Inc.
The copyright date should be just 2019.
+// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file include/stop_token + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_STOP_TOKEN +#define _GLIBCXX_STOP_TOKEN +
Please add: #if __cplusplus > 201703L here (and the corresponding #endif before the final #endif) so that this file is empty when included pre-C++20.
+#include <type_traits> +#include <memory> +#include <mutex> +#include <atomic> + +#define __cpp_lib_jthread 201907L + +namespace std _GLIBCXX_VISIBILITY(default) +{ + _GLIBCXX_BEGIN_NAMESPACE_VERSION
These BEGIN/END macros should not be indented (which has to be done manually as editors always want to indent the content following the opening brace of the namespace).
+ + class stop_source; + template<class _Callback>
s/class/typename/
+ class stop_callback; + + struct nostopstate_t { explicit nostopstate_t() = default; }; + inline constexpr nostopstate_t nostopstate(); + + class stop_token {
The opening brace should be on the next line please, in the same column as "class". (Same comment for all classes and structs in the patch).
+ public: + stop_token() noexcept = default; + + stop_token(const stop_token& __other) noexcept + : _M_state(__other._M_state) + { } + + stop_token(stop_token&& __other) noexcept + : _M_state(std::move(__other._M_state)) + { } + + ~stop_token() = default; + + stop_token& + operator=(const stop_token& __rhs) noexcept { + _M_state = __rhs._M_state; + return *this; + } + + stop_token& + operator=(stop_token&& __rhs) noexcept { + std::swap(_M_state, __rhs._M_state); + return *this; + }
This doesn't leave the RHS empty as required. I think the copy/move constructors and copy/move assignment operators can all be defined as = default and that will do the right thing.
+ + [[nodiscard]] + bool + stop_possible() const noexcept + { + return static_cast<bool>(_M_state); + } + + [[nodiscard]] + bool + stop_requested() const noexcept + { + return stop_possible() && _M_state->_M_stop_requested(); + } + + private: + friend stop_source; + template<typename _Callback> + friend class stop_callback; + + struct _Stop_cb { + void(*_M_callback)(_Stop_cb*); + _Stop_cb* _M_prev = nullptr; + _Stop_cb* _M_next = nullptr; + + template<typename _CB>
Please Use _Cb so it's not all uppercase (which is more likely to conflict with libc macros).
+ _Stop_cb(_CB&& __cb) + : _M_callback(std::move(__cb)) + { } + + static void + _S_execute(_Stop_cb* __cb) noexcept + { + __cb->_M_callback(__cb); + } + }; + + struct _Stop_state_t { + std::atomic<bool> _M_stopped; + std::mutex _M_mtx; + _Stop_cb* _M_head = nullptr; + + _Stop_state_t() + : _M_stopped{false} + { } + + bool + _M_stop_requested() + { + return _M_stopped; + } + + bool + _M_request_stop() + { + bool __stopped = false; + if (_M_stopped.compare_exchange_strong(__stopped, true)) + { + std::unique_lock<std::mutex> __lck{_M_mtx}; + while (auto __p = _M_head) + { + _M_head = __p->_M_next; + _Stop_cb::_S_execute(__p); + } + return true; + } + return false; + } + + bool + _M_register_callback(_Stop_cb* __cb) + { + std::unique_lock<std::mutex> __lck{_M_mtx}; + if (_M_stopped) + return false; + + __cb->_M_next = _M_head; + _M_head->_M_prev = __cb; + _M_head = __cb; + return true; + } + + void + _M_remove_callback(_Stop_cb* __cb) + { + std::unique_lock<std::mutex> __lck{_M_mtx}; + if (__cb == _M_head) + { + _M_head = _M_head->_M_next; + _M_head->_M_prev = nullptr; + } + else + { + __cb->_M_prev->_M_next = __cb->_M_next; + if (__cb->_M_next) + { + __cb->_M_next->_M_prev = __cb->_M_prev; + } + } + } + }; + + using _Stop_state = std::shared_ptr<_Stop_state_t>; + _Stop_state _M_state; + + explicit stop_token(_Stop_state __state) + : _M_state{std::move(__state)} + { } + }; + + class stop_source { + using _Stop_state_t = stop_token::_Stop_state_t; + using _Stop_state = stop_token::_Stop_state; + + public: + stop_source() + : _M_state(std::make_shared<_Stop_state_t>()) + { } + + explicit stop_source(std::nostopstate_t) noexcept + { } + + stop_source(const stop_source& __other) noexcept + : _M_state(__other._M_state) + { } + + stop_source(stop_source&& __other) noexcept + : _M_state(std::move(__other._M_state)) + { } + + stop_source& + operator=(const stop_source& __rhs) noexcept + { + if (_M_state != __rhs._M_state) + _M_state = __rhs._M_state; + return *this; + } + + stop_source& + operator=(stop_source&& __rhs) noexcept + { + std::swap(_M_state, __rhs._M_state); + return *this; + }
These can all be defaulted too.
+ [[nodiscard]] + bool + stop_possible() const noexcept + { + return static_cast<bool>(_M_state); + } + + [[nodiscard]] + bool + stop_requested() const noexcept + { + return stop_possible() && _M_state->_M_stop_requested(); + } + + bool + request_stop() const noexcept + { + if (stop_possible()) + return _M_state->_M_request_stop(); + return false; + } + + [[nodiscard]] + stop_token + get_token() const noexcept + { + return stop_token{_M_state}; + } + + void + swap(stop_source& __other) noexcept + { + std::swap(_M_state, __other._M_state); + } + + [[nodiscard]] + friend bool + operator==(const stop_source& __a, const stop_source& __b) noexcept + { + return __a._M_state == __b._M_state; + } + + [[nodiscard]] + friend bool + operator!=(const stop_source& __a, const stop_source& __b) noexcept + { + return __a._M_state != __b._M_state; + } + + private: + _Stop_state _M_state; + }; + + template<typename _Callback> + class [[nodiscard]] stop_callback + : private stop_token::_Stop_cb {
Opening brace on the next line, in the same column as "class".
+ using _Stop_cb = stop_token::_Stop_cb;
And then everything in the class body should be indented by another two columns.
+ using _Stop_state = stop_token::_Stop_state; + public: + using callback_type = _Callback; + + template<typename _CB,
Change to _Cb here too.