xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/bits/std_mutex.h (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1f9a78e0eSmrg // std::mutex implementation -*- C++ -*-
2f9a78e0eSmrg 
3b1e83836Smrg // Copyright (C) 2003-2022 Free Software Foundation, Inc.
4f9a78e0eSmrg //
5f9a78e0eSmrg // This file is part of the GNU ISO C++ Library.  This library is free
6f9a78e0eSmrg // software; you can redistribute it and/or modify it under the
7f9a78e0eSmrg // terms of the GNU General Public License as published by the
8f9a78e0eSmrg // Free Software Foundation; either version 3, or (at your option)
9f9a78e0eSmrg // any later version.
10f9a78e0eSmrg 
11f9a78e0eSmrg // This library is distributed in the hope that it will be useful,
12f9a78e0eSmrg // but WITHOUT ANY WARRANTY; without even the implied warranty of
13f9a78e0eSmrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14f9a78e0eSmrg // GNU General Public License for more details.
15f9a78e0eSmrg 
16f9a78e0eSmrg // Under Section 7 of GPL version 3, you are granted additional
17f9a78e0eSmrg // permissions described in the GCC Runtime Library Exception, version
18f9a78e0eSmrg // 3.1, as published by the Free Software Foundation.
19f9a78e0eSmrg 
20f9a78e0eSmrg // You should have received a copy of the GNU General Public License and
21f9a78e0eSmrg // a copy of the GCC Runtime Library Exception along with this program;
22f9a78e0eSmrg // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23f9a78e0eSmrg // <http://www.gnu.org/licenses/>.
24f9a78e0eSmrg 
25f9a78e0eSmrg /** @file bits/std_mutex.h
26f9a78e0eSmrg  *  This is an internal header file, included by other library headers.
27f9a78e0eSmrg  *  Do not attempt to use it directly. @headername{mutex}
28f9a78e0eSmrg  */
29f9a78e0eSmrg 
30f9a78e0eSmrg #ifndef _GLIBCXX_MUTEX_H
31f9a78e0eSmrg #define _GLIBCXX_MUTEX_H 1
32f9a78e0eSmrg 
33f9a78e0eSmrg #pragma GCC system_header
34f9a78e0eSmrg 
35f9a78e0eSmrg #if __cplusplus < 201103L
36f9a78e0eSmrg # include <bits/c++0x_warning.h>
37f9a78e0eSmrg #else
38f9a78e0eSmrg 
39f9a78e0eSmrg #include <system_error>
40f9a78e0eSmrg #include <bits/functexcept.h>
41f9a78e0eSmrg #include <bits/gthr.h>
42f9a78e0eSmrg 
_GLIBCXX_VISIBILITY(default)43f9a78e0eSmrg namespace std _GLIBCXX_VISIBILITY(default)
44f9a78e0eSmrg {
45f9a78e0eSmrg _GLIBCXX_BEGIN_NAMESPACE_VERSION
46f9a78e0eSmrg 
47f9a78e0eSmrg   /**
48f9a78e0eSmrg    * @defgroup mutexes Mutexes
49f9a78e0eSmrg    * @ingroup concurrency
50f9a78e0eSmrg    *
51f9a78e0eSmrg    * Classes for mutex support.
52f9a78e0eSmrg    * @{
53f9a78e0eSmrg    */
54f9a78e0eSmrg 
55f9a78e0eSmrg #ifdef _GLIBCXX_HAS_GTHREADS
56*0a307195Smrg   /// @cond undocumented
57*0a307195Smrg 
58f9a78e0eSmrg   // Common base class for std::mutex and std::timed_mutex
59f9a78e0eSmrg   class __mutex_base
60f9a78e0eSmrg   {
61f9a78e0eSmrg   protected:
62f9a78e0eSmrg     typedef __gthread_mutex_t			__native_type;
63f9a78e0eSmrg 
64f9a78e0eSmrg #ifdef __GTHREAD_MUTEX_INIT
65f9a78e0eSmrg     __native_type  _M_mutex = __GTHREAD_MUTEX_INIT;
66f9a78e0eSmrg 
67f9a78e0eSmrg     constexpr __mutex_base() noexcept = default;
68f9a78e0eSmrg #else
69f9a78e0eSmrg     __native_type  _M_mutex;
70f9a78e0eSmrg 
71f9a78e0eSmrg     __mutex_base() noexcept
72f9a78e0eSmrg     {
73f9a78e0eSmrg       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
74f9a78e0eSmrg       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
75f9a78e0eSmrg     }
76f9a78e0eSmrg 
77f9a78e0eSmrg     ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); }
78f9a78e0eSmrg #endif
79f9a78e0eSmrg 
80f9a78e0eSmrg     __mutex_base(const __mutex_base&) = delete;
81f9a78e0eSmrg     __mutex_base& operator=(const __mutex_base&) = delete;
82f9a78e0eSmrg   };
83*0a307195Smrg   /// @endcond
84f9a78e0eSmrg 
85*0a307195Smrg   /** The standard mutex type.
86*0a307195Smrg    *
87*0a307195Smrg    * A simple, non-recursive, non-timed mutex.
88*0a307195Smrg    *
89*0a307195Smrg    * Do not call `lock()` and `unlock()` directly, use a scoped lock type
90*0a307195Smrg    * such as `std::unique_lock`, `std::lock_guard`, or (since C++17)
91*0a307195Smrg    * `std::scoped_lock`.
92*0a307195Smrg    *
93*0a307195Smrg    * @headerfile mutex
94*0a307195Smrg    * @since C++11
95*0a307195Smrg    */
96f9a78e0eSmrg   class mutex : private __mutex_base
97f9a78e0eSmrg   {
98f9a78e0eSmrg   public:
99f9a78e0eSmrg     typedef __native_type* 			native_handle_type;
100f9a78e0eSmrg 
101f9a78e0eSmrg #ifdef __GTHREAD_MUTEX_INIT
102f9a78e0eSmrg     constexpr
103f9a78e0eSmrg #endif
104f9a78e0eSmrg     mutex() noexcept = default;
105f9a78e0eSmrg     ~mutex() = default;
106f9a78e0eSmrg 
107f9a78e0eSmrg     mutex(const mutex&) = delete;
108f9a78e0eSmrg     mutex& operator=(const mutex&) = delete;
109f9a78e0eSmrg 
110f9a78e0eSmrg     void
111f9a78e0eSmrg     lock()
112f9a78e0eSmrg     {
113f9a78e0eSmrg       int __e = __gthread_mutex_lock(&_M_mutex);
114f9a78e0eSmrg 
115f9a78e0eSmrg       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
116f9a78e0eSmrg       if (__e)
117f9a78e0eSmrg 	__throw_system_error(__e);
118f9a78e0eSmrg     }
119f9a78e0eSmrg 
120f9a78e0eSmrg     bool
121f9a78e0eSmrg     try_lock() noexcept
122f9a78e0eSmrg     {
123f9a78e0eSmrg       // XXX EINVAL, EAGAIN, EBUSY
124f9a78e0eSmrg       return !__gthread_mutex_trylock(&_M_mutex);
125f9a78e0eSmrg     }
126f9a78e0eSmrg 
127f9a78e0eSmrg     void
128f9a78e0eSmrg     unlock()
129f9a78e0eSmrg     {
130f9a78e0eSmrg       // XXX EINVAL, EAGAIN, EPERM
131f9a78e0eSmrg       __gthread_mutex_unlock(&_M_mutex);
132f9a78e0eSmrg     }
133f9a78e0eSmrg 
134f9a78e0eSmrg     native_handle_type
135b17d1066Smrg     native_handle() noexcept
136f9a78e0eSmrg     { return &_M_mutex; }
137f9a78e0eSmrg   };
138f9a78e0eSmrg 
139*0a307195Smrg   /// @cond undocumented
140*0a307195Smrg 
141b1e83836Smrg   // Implementation details for std::condition_variable
142b1e83836Smrg   class __condvar
143b1e83836Smrg   {
144b1e83836Smrg     using timespec = __gthread_time_t;
145b1e83836Smrg 
146b1e83836Smrg   public:
147b1e83836Smrg     __condvar() noexcept
148b1e83836Smrg     {
149b1e83836Smrg #ifndef __GTHREAD_COND_INIT
150b1e83836Smrg       __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
151b1e83836Smrg #endif
152b1e83836Smrg     }
153b1e83836Smrg 
154b1e83836Smrg     ~__condvar()
155b1e83836Smrg     {
156b1e83836Smrg       int __e __attribute__((__unused__)) = __gthread_cond_destroy(&_M_cond);
157b1e83836Smrg       __glibcxx_assert(__e != EBUSY); // threads are still blocked
158b1e83836Smrg     }
159b1e83836Smrg 
160b1e83836Smrg     __condvar(const __condvar&) = delete;
161b1e83836Smrg     __condvar& operator=(const __condvar&) = delete;
162b1e83836Smrg 
163b1e83836Smrg     __gthread_cond_t* native_handle() noexcept { return &_M_cond; }
164b1e83836Smrg 
165b1e83836Smrg     // Expects: Calling thread has locked __m.
166b1e83836Smrg     void
167b1e83836Smrg     wait(mutex& __m)
168b1e83836Smrg     {
169b1e83836Smrg       int __e __attribute__((__unused__))
170b1e83836Smrg 	= __gthread_cond_wait(&_M_cond, __m.native_handle());
171b1e83836Smrg       __glibcxx_assert(__e == 0);
172b1e83836Smrg     }
173b1e83836Smrg 
174b1e83836Smrg     void
175b1e83836Smrg     wait_until(mutex& __m, timespec& __abs_time)
176b1e83836Smrg     {
177b1e83836Smrg       __gthread_cond_timedwait(&_M_cond, __m.native_handle(), &__abs_time);
178b1e83836Smrg     }
179b1e83836Smrg 
180b1e83836Smrg #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
181b1e83836Smrg     void
182b1e83836Smrg     wait_until(mutex& __m, clockid_t __clock, timespec& __abs_time)
183b1e83836Smrg     {
184b1e83836Smrg       pthread_cond_clockwait(&_M_cond, __m.native_handle(), __clock,
185b1e83836Smrg 			     &__abs_time);
186b1e83836Smrg     }
187b1e83836Smrg #endif
188b1e83836Smrg 
189b1e83836Smrg     void
190b1e83836Smrg     notify_one() noexcept
191b1e83836Smrg     {
192b1e83836Smrg       int __e __attribute__((__unused__)) = __gthread_cond_signal(&_M_cond);
193b1e83836Smrg       __glibcxx_assert(__e == 0);
194b1e83836Smrg     }
195b1e83836Smrg 
196b1e83836Smrg     void
197b1e83836Smrg     notify_all() noexcept
198b1e83836Smrg     {
199b1e83836Smrg       int __e __attribute__((__unused__)) = __gthread_cond_broadcast(&_M_cond);
200b1e83836Smrg       __glibcxx_assert(__e == 0);
201b1e83836Smrg     }
202b1e83836Smrg 
203b1e83836Smrg   protected:
204b1e83836Smrg #ifdef __GTHREAD_COND_INIT
205b1e83836Smrg     __gthread_cond_t _M_cond = __GTHREAD_COND_INIT;
206b1e83836Smrg #else
207b1e83836Smrg     __gthread_cond_t _M_cond;
208b1e83836Smrg #endif
209b1e83836Smrg   };
210*0a307195Smrg   /// @endcond
211b1e83836Smrg 
212f9a78e0eSmrg #endif // _GLIBCXX_HAS_GTHREADS
213f9a78e0eSmrg 
214f9a78e0eSmrg   /// Do not acquire ownership of the mutex.
215f9a78e0eSmrg   struct defer_lock_t { explicit defer_lock_t() = default; };
216f9a78e0eSmrg 
217f9a78e0eSmrg   /// Try to acquire ownership of the mutex without blocking.
218f9a78e0eSmrg   struct try_to_lock_t { explicit try_to_lock_t() = default; };
219f9a78e0eSmrg 
220f9a78e0eSmrg   /// Assume the calling thread has already obtained mutex ownership
221f9a78e0eSmrg   /// and manage it.
222f9a78e0eSmrg   struct adopt_lock_t { explicit adopt_lock_t() = default; };
223f9a78e0eSmrg 
224f9a78e0eSmrg   /// Tag used to prevent a scoped lock from acquiring ownership of a mutex.
225b17d1066Smrg   _GLIBCXX17_INLINE constexpr defer_lock_t	defer_lock { };
226f9a78e0eSmrg 
227f9a78e0eSmrg   /// Tag used to prevent a scoped lock from blocking if a mutex is locked.
228b17d1066Smrg   _GLIBCXX17_INLINE constexpr try_to_lock_t	try_to_lock { };
229f9a78e0eSmrg 
230f9a78e0eSmrg   /// Tag used to make a scoped lock take ownership of a locked mutex.
231b17d1066Smrg   _GLIBCXX17_INLINE constexpr adopt_lock_t	adopt_lock { };
232f9a78e0eSmrg 
233f9a78e0eSmrg   /** @brief A simple scoped lock type.
234f9a78e0eSmrg    *
235f9a78e0eSmrg    * A lock_guard controls mutex ownership within a scope, releasing
236f9a78e0eSmrg    * ownership in the destructor.
237*0a307195Smrg    *
238*0a307195Smrg    * @headerfile mutex
239*0a307195Smrg    * @since C++11
240f9a78e0eSmrg    */
241f9a78e0eSmrg   template<typename _Mutex>
242f9a78e0eSmrg     class lock_guard
243f9a78e0eSmrg     {
244f9a78e0eSmrg     public:
245f9a78e0eSmrg       typedef _Mutex mutex_type;
246f9a78e0eSmrg 
247f9a78e0eSmrg       explicit lock_guard(mutex_type& __m) : _M_device(__m)
248f9a78e0eSmrg       { _M_device.lock(); }
249f9a78e0eSmrg 
250b17d1066Smrg       lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m)
251f9a78e0eSmrg       { } // calling thread owns mutex
252f9a78e0eSmrg 
253f9a78e0eSmrg       ~lock_guard()
254f9a78e0eSmrg       { _M_device.unlock(); }
255f9a78e0eSmrg 
256f9a78e0eSmrg       lock_guard(const lock_guard&) = delete;
257f9a78e0eSmrg       lock_guard& operator=(const lock_guard&) = delete;
258f9a78e0eSmrg 
259f9a78e0eSmrg     private:
260f9a78e0eSmrg       mutex_type&  _M_device;
261f9a78e0eSmrg     };
262f9a78e0eSmrg 
263a448f87cSmrg   /// @} group mutexes
264f9a78e0eSmrg _GLIBCXX_END_NAMESPACE_VERSION
265f9a78e0eSmrg } // namespace
266f9a78e0eSmrg #endif // C++11
267f9a78e0eSmrg #endif // _GLIBCXX_MUTEX_H
268