1// future -*- C++ -*-
2
3// Copyright (C) 2009-2022 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25#include <future>
26#include <bits/functexcept.h>
27
28#if __has_cpp_attribute(clang::require_constant_initialization)
29#  define __constinit [[clang::require_constant_initialization]]
30#endif
31
32namespace
33{
34  struct future_error_category final : public std::error_category
35  {
36    const char*
37    name() const noexcept final
38    { return "future"; }
39
40    _GLIBCXX_DEFAULT_ABI_TAG
41    std::string
42    message(int __ec) const final
43    {
44      std::string __msg;
45      switch (std::future_errc(__ec))
46      {
47      case std::future_errc::broken_promise:
48          __msg = "Broken promise";
49          break;
50      case std::future_errc::future_already_retrieved:
51          __msg = "Future already retrieved";
52          break;
53      case std::future_errc::promise_already_satisfied:
54          __msg = "Promise already satisfied";
55          break;
56      case std::future_errc::no_state:
57          __msg = "No associated state";
58          break;
59      default:
60          __msg = "Unknown error";
61          break;
62      }
63      return __msg;
64    }
65  };
66
67  struct constant_init
68  {
69    union {
70      unsigned char unused;
71      future_error_category cat;
72    };
73    constexpr constant_init() : cat() { }
74    ~constant_init() { /* do nothing, union member is not destroyed */ }
75  };
76
77  __constinit constant_init future_category_instance{};
78}
79
80namespace std _GLIBCXX_VISIBILITY(default)
81{
82_GLIBCXX_BEGIN_NAMESPACE_VERSION
83
84  void
85  __throw_future_error(int __i __attribute__((unused)))
86  { _GLIBCXX_THROW_OR_ABORT(future_error(make_error_code(future_errc(__i)))); }
87
88  const error_category& future_category() noexcept
89  { return future_category_instance.cat; }
90
91  future_error::~future_error() noexcept { }
92
93  const char*
94  future_error::what() const noexcept { return logic_error::what(); }
95
96#ifdef _GLIBCXX_HAS_GTHREADS
97  __future_base::_Result_base::_Result_base() = default;
98
99  __future_base::_Result_base::~_Result_base() = default;
100
101  void
102  __future_base::_State_baseV2::_Make_ready::_S_run(void* p)
103  {
104    unique_ptr<_Make_ready> mr{static_cast<_Make_ready*>(p)};
105    if (auto state = mr->_M_shared_state.lock())
106      {
107	// Use release MO to synchronize with observers of the ready state.
108	state->_M_status._M_store_notify_all(_Status::__ready,
109	    memory_order_release);
110      }
111  }
112
113  // defined in src/c++11/condition_variable.cc
114  extern void
115  __at_thread_exit(__at_thread_exit_elt* elt);
116
117  void
118  __future_base::_State_baseV2::_Make_ready::_M_set()
119  {
120    _M_cb = &_Make_ready::_S_run;
121    __at_thread_exit(this);
122  }
123#endif // _GLIBCXX_HAS_GTHREADS
124
125_GLIBCXX_END_NAMESPACE_VERSION
126} // namespace std
127