sync.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef B10_THREAD_SYNC_H
  15. #define B10_THREAD_SYNC_H
  16. #include <exceptions/exceptions.h>
  17. #include <boost/noncopyable.hpp>
  18. #include <cstdlib> // for NULL.
  19. namespace isc {
  20. namespace util {
  21. namespace thread {
  22. class CondVar;
  23. /// \brief Mutex with very simple interface
  24. ///
  25. /// Since mutexes are very system dependant, we create our own wrapper around
  26. /// whatever is available on the system and hide it.
  27. ///
  28. /// To use this mutex, create it and then lock and unlock it by creating the
  29. /// Mutex::Locker object.
  30. ///
  31. /// Also, as mutex is a low-level system object, an error might happen at any
  32. /// operation with it. We convert many errors to the isc::InvalidOperation,
  33. /// since the errors usually happen only when used in a wrong way. Any methods
  34. /// or constructors in this class can throw. Allocation errors are converted
  35. /// to std::bad_alloc (for example when OS-dependant limit of mutexes is
  36. /// exceeded). Some errors which usually mean a programmer error abort the
  37. /// program, since there could be no safe way to recover from them.
  38. ///
  39. /// The current interface is somewhat minimalistic. If we ever need more, we
  40. /// can add it later.
  41. class Mutex : boost::noncopyable {
  42. public:
  43. /// \brief Constructor.
  44. ///
  45. /// Creates a mutex. It is a non-recursive mutex (can be locked just once,
  46. /// if the same threads tries to lock it again, Bad Things Happen).
  47. ///
  48. /// Depending on compilation parameters and OS, the mutex may or may not
  49. /// do some error and sanity checking. However, such checking is meant
  50. /// only to aid development, not rely on it as a feature.
  51. ///
  52. /// \throw std::bad_alloc In case allocation of something (memory, the
  53. /// OS mutex) fails.
  54. /// \throw isc::InvalidOperation Other unspecified errors around the mutex.
  55. /// This should be rare.
  56. Mutex();
  57. /// \brief Destructor.
  58. ///
  59. /// Destroys the mutex. It is not allowed to destroy a mutex which is
  60. /// currently locked. This means a Locker created with this Mutex must
  61. /// never live longer than the Mutex itself.
  62. ~Mutex();
  63. /// \brief This holds a lock on a Mutex.
  64. ///
  65. /// To lock a mutex, create a locker. It'll get unlocked when the locker
  66. /// is destroyed.
  67. ///
  68. /// If you create the locker on the stack or using some other "garbage
  69. /// collecting" mechanism (auto_ptr, for example), it ensures exception
  70. /// safety with regards to the mutex - it'll get released on the exit
  71. /// of function no matter by what means.
  72. class Locker : boost::noncopyable {
  73. public:
  74. /// \brief Exception thrown when the mutex is already locked and
  75. /// a non-blocking locker is attempted around it.
  76. struct AlreadyLocked : public isc::InvalidParameter {
  77. AlreadyLocked(const char* file, size_t line, const char* what) :
  78. isc::InvalidParameter(file, line, what)
  79. {}
  80. };
  81. /// \brief Constructor.
  82. ///
  83. /// Locks the mutex. May block for extended period of time if
  84. /// \c block is true.
  85. ///
  86. /// \throw isc::InvalidOperation when OS reports error. This usually
  87. /// means an attempt to use the mutex in a wrong way (locking
  88. /// a mutex second time from the same thread, for example).
  89. /// \throw AlreadyLocked if \c block is false and the mutex is
  90. /// already locked.
  91. Locker(Mutex& mutex, bool block = true) :
  92. mutex_(mutex)
  93. {
  94. if (block) {
  95. mutex.lock();
  96. } else {
  97. if (!mutex.tryLock()) {
  98. isc_throw(AlreadyLocked, "The mutex is already locked");
  99. }
  100. }
  101. }
  102. /// \brief Destructor.
  103. ///
  104. /// Unlocks the mutex.
  105. ~Locker() {
  106. mutex_.unlock();
  107. }
  108. private:
  109. Mutex& mutex_;
  110. };
  111. /// \brief If the mutex is currently locked
  112. ///
  113. /// This is debug aiding method only. And it might be unavailable in
  114. /// non-debug build (because keeping the state might be needlesly
  115. /// slow).
  116. ///
  117. /// \todo Disable in non-debug build
  118. bool locked() const;
  119. /// \brief Lock the mutex
  120. ///
  121. /// This method blocks until the mutex can be locked.
  122. ///
  123. /// Please consider not using this method directly and instead using
  124. /// a Mutex::Locker object instead.
  125. void lock();
  126. /// \brief Try to lock the mutex
  127. ///
  128. /// This method doesn't block and returns immediately with a status
  129. /// on whether the lock operation was successful.
  130. ///
  131. /// Please consider not using this method directly and instead using
  132. /// a Mutex::Locker object instead.
  133. ///
  134. /// \return true if the lock was successful, false otherwise.
  135. bool tryLock();
  136. /// \brief Unlock the mutex
  137. ///
  138. /// Please consider not using this method directly and instead using
  139. /// a Mutex::Locker object instead.
  140. void unlock();
  141. private:
  142. friend class CondVar;
  143. // Commonly called after acquiring the lock, checking and updating
  144. // internal state for debug.
  145. void postLockAction();
  146. // Commonly called before releasing the lock, checking and updating
  147. // internal state for debug.
  148. //
  149. // If throw_ok is true, it throws \c isc::InvalidOperation when the check
  150. // fails; otherwise it aborts the process. This parameter must be set
  151. // to false if the call to this shouldn't result in an exception (e.g.
  152. // when called from a destructor).
  153. void preUnlockAction(bool throw_ok);
  154. class Impl;
  155. Impl* impl_;
  156. };
  157. /// \brief Encapsulation for a condition variable.
  158. ///
  159. /// This class provides a simple encapsulation of condition variable for
  160. /// inter-thread synchronization. It has similar but simplified interface as
  161. /// that for \c pthread_cond_ variants.
  162. ///
  163. /// It uses the \c Mutex class object for the mutex used with the condition
  164. /// variable. Since for normal applications the internal \c Mutex::Locker
  165. /// class is the only available interface to acquire a lock, sample code
  166. /// for waiting on a condition variable would look like this:
  167. /// \code
  168. /// CondVar cond;
  169. /// Mutex mutex;
  170. /// {
  171. /// Mutex::Locker locker(mutex);
  172. /// while (some_condition) {
  173. /// cond.wait(mutex);
  174. /// }
  175. /// // do something under the protection of locker
  176. /// } // lock is released here
  177. /// \endcode
  178. /// Note that \c mutex passed to the \c wait() method must be the same one
  179. /// used to construct the \c locker.
  180. ///
  181. /// Right now there is no equivalent to pthread_cond_broadcast() or
  182. /// pthread_cond_timedwait() in this class, because this class is meant
  183. /// for internal development of BIND 10 and we don't need these at the
  184. /// moment. If and when we need these interfaces they can be added at that
  185. /// point.
  186. ///
  187. /// \note This class is defined as a friend class of \c Mutex and directly
  188. /// refers to and modifies private internals of the \c Mutex class. It breaks
  189. /// the assumption that the lock is only acquired or released via the
  190. /// \c Locker class and breaks other integrity assumption on \c Mutex,
  191. /// thereby making it more fragile, but we couldn't find other way to
  192. /// implement a safe and still simple realization of condition variables.
  193. /// So, this is a kind of compromise. If this class is needed to be
  194. /// extended, first consider a way to use public interfaces of \c Mutex;
  195. /// do not easily rely on the fact that this class is a friend of it.
  196. class CondVar : boost::noncopyable {
  197. public:
  198. /// \brief Constructor.
  199. ///
  200. /// \throw std::bad_alloc memory allocation failure
  201. /// \throw isc::Unexpected other unexpected shortage of system resource
  202. CondVar();
  203. /// \brief Destructor.
  204. ///
  205. /// An object of this class must not be destroyed while some thread
  206. /// is waiting on it. If this condition isn't met the destructor will
  207. /// terminate the program.
  208. ~CondVar();
  209. /// \brief Wait on the condition variable.
  210. ///
  211. /// This method works like \c pthread_cond_wait(). For mutex it takes
  212. /// an \c Mutex class object. A lock for the mutex must have been
  213. /// acquired. If this condition isn't met, it can throw an exception
  214. /// (in the debug mode build) or result in undefined behavior.
  215. ///
  216. /// The lock will be automatically released within this method, and
  217. /// will be re-acquired on the exit of this method.
  218. ///
  219. /// \throw isc::InvalidOperation mutex isn't locked
  220. /// \throw isc::BadValue mutex is not a valid \c Mutex object
  221. ///
  222. /// \param mutex A \c Mutex object to be released on wait().
  223. void wait(Mutex& mutex);
  224. /// \brief Unblock a thread waiting for the condition variable.
  225. ///
  226. /// This method wakes one of other threads (if any) waiting on this object
  227. /// via the \c wait() call.
  228. ///
  229. /// This method never throws; if some unexpected low level error happens
  230. /// it terminates the program.
  231. void signal();
  232. private:
  233. class Impl;
  234. Impl* impl_;
  235. };
  236. } // namespace thread
  237. } // namespace util
  238. } // namespace isc
  239. #endif
  240. // Local Variables:
  241. // mode: c++
  242. // End: