libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
posix_locking.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_UNIX_POSIX_LOCKING_HPP
2 #define LIBJMMCG_UNIX_POSIX_LOCKING_HPP
3 
4 /******************************************************************************
5 ** Copyright © 2004 by J.M.McGuiness, coder@hussar.me.uk
6 **
7 ** This library is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU Lesser General Public
9 ** License as published by the Free Software Foundation; either
10 ** version 2.1 of the License, or (at your option) any later version.
11 **
12 ** This library is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ** Lesser General Public License for more details.
16 **
17 ** You should have received a copy of the GNU Lesser General Public
18 ** License along with this library; if not, write to the Free Software
19 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
22 #include <unistd.h>
23 
24 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE { namespace ppd { namespace pthreads {
25 
26  class condition_var {
27  public:
28  typedef api_lock_traits<ppd::generic_traits::api_type::posix_pthreads, heavyweight_threading> lock_traits;
29  typedef lock_traits::atomic_state_type atomic_state_type;
30  typedef lock_traits::exception_type exception_type;
31 
32  explicit __stdcall condition_var(const int shared=PTHREAD_PROCESS_PRIVATE) noexcept(false) FORCE_INLINE;
33  condition_var(condition_var const &)=delete;
34  __stdcall ~condition_var() noexcept(true) FORCE_INLINE;
35 
36  operator pthread_cond_t const *() const noexcept(true) FORCE_INLINE {
37  return &cond_var;
38  }
39  operator pthread_cond_t *() noexcept(true) FORCE_INLINE {
40  return &cond_var;
41  }
42 
43  private:
44  class attr;
45 
46  pthread_cond_t cond_var;
47  };
48 
49  /**
50  * Note that this is not the most efficient mutex, but it is safer than default-created mutexes, as it uses PTHREAD_MUTEX_ERRORCHECK semantics [1].
51  *
52  * [1] https://www.securecoding.cert.org/confluence/display/seccode/POS04-C.+Avoid+using+PTHREAD_MUTEX_NORMAL+type+mutex+locks
53  *
54  * \see PTHREAD_PROCESS_PRIVATE
55  * \see PTHREAD_MUTEX_ERRORCHECK
56  */
58  public:
59  typedef lock::lockable<api_lock_traits<ppd::generic_traits::api_type::posix_pthreads, heavyweight_threading> > base_t;
70  /**
71  To assist in allowing compile-time computation of the algorithmic order of the threading model.
72  */
74 
75  __stdcall anon_mutex() noexcept(false) FORCE_INLINE;
76  anon_mutex(anon_mutex const &)=delete;
77  virtual __stdcall ~anon_mutex() noexcept(true) FORCE_INLINE;
78 
79  operator api_mutex_type *() noexcept(true) FORCE_INLINE;
80  atomic_state_type __fastcall lock(const timeout_type timeout) noexcept(true) override FORCE_INLINE final;
81  atomic_state_type __fastcall lock() noexcept(true) override FORCE_INLINE final;
82  atomic_state_type __fastcall unlock() noexcept(true) override FORCE_INLINE final;
83  void decay() noexcept(true) FORCE_INLINE;
84 
85  protected:
86  explicit __stdcall anon_mutex(const int shared, const int err_chk=PTHREAD_MUTEX_ERRORCHECK) noexcept(false) FORCE_INLINE;
87 
88  private:
89  friend class mutex;
90  class attr;
91 
92  api_mutex_type mutex;
93  };
94 
95  class recursive_anon_mutex final : public anon_mutex {
96  public:
97  typedef anon_mutex base_t;
98  typedef base_t::lock_traits lock_traits;
99  typedef base_t::atomic_state_type atomic_state_type;
101  typedef lock::in_process<recursive_anon_mutex> lock_type;
104  typedef lock::in_process_unlockable<recursive_anon_mutex> unlockable_type;
107 
108  __stdcall recursive_anon_mutex() noexcept(false) FORCE_INLINE
109  : anon_mutex(PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_RECURSIVE) {
110  }
111  __stdcall ~recursive_anon_mutex() noexcept(true) FORCE_INLINE {}
112  };
113 
114  class mutex final : public anon_mutex {
115  public:
117  typedef base_t::lock_traits lock_traits;
118  typedef base_t::atomic_state_type atomic_state_type;
120  typedef lock::in_process<mutex> lock_type;
126 
127  __stdcall FORCE_INLINE mutex() noexcept(false)
128  : anon_mutex(PTHREAD_PROCESS_SHARED) {
129  }
130  __stdcall ~mutex() noexcept(true) FORCE_INLINE {}
131  };
132 
133  class recursive_mutex final : public anon_mutex {
134  public:
135  typedef lock::in_process<recursive_mutex> lock_type;
138  typedef lock::in_process_unlockable<recursive_mutex> unlockable_type;
141 
142  __stdcall recursive_mutex() noexcept(false) FORCE_INLINE
143  : anon_mutex(PTHREAD_PROCESS_SHARED, PTHREAD_MUTEX_RECURSIVE) {
144  }
145  __stdcall ~recursive_mutex() noexcept(true) FORCE_INLINE {}
146  };
147 
149  public:
150  typedef lock::lockable_settable<api_lock_traits<ppd::generic_traits::api_type::posix_pthreads, heavyweight_threading> > base_t;
154  typedef int count_type;
160 
161  /**
162  To assist in allowing compile-time computation of the algorithmic order of the threading model.
163  */
165 
166  /**
167  Manual reset and initially signalled.
168  */
169  explicit __stdcall anon_semaphore(const atomic_state_type state) noexcept(false) FORCE_INLINE;
171  virtual __stdcall ~anon_semaphore() noexcept(true) FORCE_INLINE;
172 
173  operator api_event_type *() noexcept(true) FORCE_INLINE;
174  atomic_state_type __fastcall set() noexcept(true) override FORCE_INLINE;
175  atomic_state_type __fastcall reset() noexcept(true) override FORCE_INLINE;
176  lock_result_type __fastcall try_lock() noexcept(true) override FORCE_INLINE;
177  lock_result_type __fastcall lock() noexcept(false) override FORCE_INLINE;
178  lock_result_type __fastcall lock(const timeout_type period) noexcept(false) override FORCE_INLINE;
179  lock_result_type __fastcall unlock() noexcept(true) override FORCE_INLINE;
180  void clear() noexcept(true) FORCE_INLINE;
181  void decay() noexcept(true) FORCE_INLINE {}
182  count_type __fastcall count() const noexcept(false) FORCE_INLINE;
183 
184  private:
185  friend class semaphore;
186 
187  mutable sem_t sem;
188 
189  explicit __stdcall anon_semaphore(const atomic_state_type state, int shared) noexcept(false);
190  };
191 
193  public:
194  typedef lock::lockable_settable<api_lock_traits<ppd::generic_traits::api_type::posix_pthreads, heavyweight_threading> > base_t;
199  typedef atomic_t::count_type count_type;
204 
205  /**
206  To assist in allowing compile-time computation of the algorithmic order of the threading model.
207  */
209 
210  /**
211  Manual reset and initially signalled.
212  */
213  explicit __stdcall semaphore(const atomic_state_type state=lock_traits::atom_set) noexcept(false) FORCE_INLINE
214  : event_(state,1) {
215  }
216  semaphore(semaphore const &)=delete;
217  __stdcall ~semaphore() noexcept(true) FORCE_INLINE {}
218 
219  operator api_event_type *() noexcept(true) FORCE_INLINE {
220  return static_cast<api_event_type *>(event_);
221  }
222  atomic_state_type __fastcall set() noexcept(true) override FORCE_INLINE {
223  return event_.set();
224  }
225  atomic_state_type __fastcall reset() noexcept(true) override FORCE_INLINE {
226  return event_.reset();
227  }
228  atomic_state_type __fastcall try_lock() noexcept(true) override FORCE_INLINE {
229  return event_.try_lock();
230  }
231  atomic_state_type __fastcall lock() noexcept(false) override FORCE_INLINE {
232  return event_.lock();
233  }
234  atomic_state_type __fastcall unlock() noexcept(true) override {
235  return event_.unlock();
236  }
237  void decay() noexcept(true) FORCE_INLINE {}
238  count_type __fastcall count() const noexcept(true) FORCE_INLINE {
239  return event_.count();
240  }
241 
242  protected:
243  atomic_state_type __fastcall lock(const timeout_type period) noexcept(false) override FORCE_INLINE {
244  return event_.lock(period);
245  }
246 
247  private:
249  };
250 
251  /// An anonymous mutex-like atomic object that is non-recursive.
252  /**
253  This object can be unlocked on a different thread from that which it was locked on. Moreover if thread A contains a reference to this atomic object and locks it, then subsequently attempts to re-gain the lock, thus blocking thread A (as the object is locked), and thread B also has a reference to this atomic object, and unlocks it, then thread A will be released.
254  This atomic object is implemented via an anonymous event.
255 
256  \see anon_event
257  */
258  class nonrecursive_anon_mutex final : public lock::lockable<api_lock_traits<ppd::generic_traits::api_type::posix_pthreads, heavyweight_threading>> {
259  public:
260  typedef lock::lockable<api_lock_traits<ppd::generic_traits::api_type::posix_pthreads, heavyweight_threading> > base_t;
264  typedef lock::in_process<nonrecursive_anon_mutex> lock_type;
267  typedef lock::in_process_unlockable<nonrecursive_anon_mutex> unlockable_type;
270  /**
271  To assist in allowing compile-time computation of the algorithmic order of the threading model.
272  */
274 
275  private:
276  anon_semaphore event_{lock_traits::atom_set};
277 
278  public:
279  __stdcall nonrecursive_anon_mutex() noexcept(noexcept(anon_semaphore(lock_traits::atom_set))) FORCE_INLINE;
280  nonrecursive_anon_mutex(nonrecursive_anon_mutex const &)=delete;
281  __stdcall ~nonrecursive_anon_mutex() noexcept(true) FORCE_INLINE;
282 
283  atomic_state_type __fastcall lock(const timeout_type timeout) noexcept(noexcept(event_.lock(timeout))) override FORCE_INLINE;
284  atomic_state_type __fastcall lock() noexcept(noexcept(event_.lock())) override FORCE_INLINE;
285  atomic_state_type __fastcall unlock() noexcept(noexcept(event_.set())) override FORCE_INLINE;
286  void decay() noexcept(true) FORCE_INLINE;
287  };
288 
289 } } } }
290 
292 
293 #endif