read_write_lock.hpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /****************************************************************************
  2. *
  3. * Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
  4. *
  5. * This file is part of the FreeRTOS Add-ons project.
  6. *
  7. * Source Code:
  8. * https://github.com/michaelbecker/freertos-addons
  9. *
  10. * Project Page:
  11. * http://michaelbecker.github.io/freertos-addons/
  12. *
  13. * On-line Documentation:
  14. * http://michaelbecker.github.io/freertos-addons/docs/html/index.html
  15. *
  16. * Permission is hereby granted, free of charge, to any person obtaining a
  17. * copy of this software and associated documentation files
  18. * (the "Software"), to deal in the Software without restriction, including
  19. * without limitation the rights to use, copy, modify, merge, publish,
  20. * distribute, sublicense, and/or sell copies of the Software, and to
  21. * permit persons to whom the Software is furnished to do so,subject to the
  22. * following conditions:
  23. *
  24. * + The above copyright notice and this permission notice shall be included
  25. * in all copies or substantial portions of the Software.
  26. * + Credit is appreciated, but not required, if you find this project
  27. * useful enough to include in your application, product, device, etc.
  28. *
  29. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  30. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  31. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  32. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  33. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  34. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  35. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  36. *
  37. ***************************************************************************/
  38. #ifndef READ_WRITE_LOCK_HPP_
  39. #define READ_WRITE_LOCK_HPP_
  40. /**
  41. * C++ exceptions are used by default when constructors fail.
  42. * If you do not want this behavior, define the following in your makefile
  43. * or project. Note that in most / all cases when a constructor fails,
  44. * it's a fatal error. In the cases when you've defined this, the new
  45. * default behavior will be to issue a configASSERT() instead.
  46. */
  47. #ifndef CPP_FREERTOS_NO_EXCEPTIONS
  48. #include <exception>
  49. #include <string>
  50. #include <cstdio>
  51. #ifdef CPP_FREERTOS_NO_CPP_STRINGS
  52. #error "FreeRTOS-Addons require C++ Strings if you are using exceptions"
  53. #endif
  54. #endif
  55. #include "FreeRTOS.h"
  56. #include "semphr.h"
  57. namespace cpp_freertos {
  58. #ifndef CPP_FREERTOS_NO_EXCEPTIONS
  59. /**
  60. * This is the exception that is thrown if a ReadWriteLock constructor fails.
  61. */
  62. class ReadWriteLockCreateException : public std::exception {
  63. public:
  64. /**
  65. * Create the exception.
  66. */
  67. ReadWriteLockCreateException()
  68. {
  69. sprintf(errorString, "ReadWriteLock Constructor Failed");
  70. }
  71. /**
  72. * Get what happened as a string.
  73. * We are overriding the base implementation here.
  74. */
  75. virtual const char *what() const throw()
  76. {
  77. return errorString;
  78. }
  79. private:
  80. /**
  81. * A text string representing what failed.
  82. */
  83. char errorString[80];
  84. };
  85. #endif
  86. /**
  87. * Abstract base class encapsulating a Reader/Writer lock.
  88. *
  89. * These locks are based on mutexs and cannot be used in any way from
  90. * ISR context. Likewise, these locks block indefinitely.
  91. *
  92. * @note It is expected that an application will instantiate one of the
  93. * derived classes and use that object for synchronization. It is
  94. * not expected that a user or application will derive from these
  95. * classes.
  96. */
  97. class ReadWriteLock {
  98. /////////////////////////////////////////////////////////////////////////
  99. //
  100. // Public API
  101. //
  102. /////////////////////////////////////////////////////////////////////////
  103. public:
  104. /**
  105. * Constructor
  106. *
  107. * @throws ReadWriteLockCreateException on failure.
  108. */
  109. ReadWriteLock();
  110. /**
  111. * Destructor
  112. */
  113. virtual ~ReadWriteLock();
  114. /**
  115. * Take the lock as a Reader.
  116. * This allows multiple reader access.
  117. */
  118. virtual void ReaderLock() = 0;
  119. /**
  120. * Unlock the Reader.
  121. */
  122. virtual void ReaderUnlock() = 0;
  123. /**
  124. * Take the lock as a Writer.
  125. * This allows only one thread access.
  126. */
  127. virtual void WriterLock() = 0;
  128. /**
  129. * Unlock the Writer.
  130. */
  131. virtual void WriterUnlock() = 0;
  132. /////////////////////////////////////////////////////////////////////////
  133. //
  134. // Protected API
  135. // Not intended for use by application code.
  136. //
  137. /////////////////////////////////////////////////////////////////////////
  138. protected:
  139. /**
  140. * How many active readers are there.
  141. */
  142. int ReadCount;
  143. /**
  144. * Protect ReadCount.
  145. */
  146. SemaphoreHandle_t ReadLock;
  147. /**
  148. * Protect this resource from multiple writer access, or
  149. * from Reader access when a writer is changing something.
  150. */
  151. SemaphoreHandle_t ResourceLock;
  152. };
  153. /**
  154. * Concrete derived class that implements a Reader/Writer lock
  155. * that favors the Readers. That is, with enough aggressive readers,
  156. * a Writer may starve.
  157. */
  158. class ReadWriteLockPreferReader : public ReadWriteLock {
  159. /////////////////////////////////////////////////////////////////////////
  160. //
  161. // Public API
  162. //
  163. /////////////////////////////////////////////////////////////////////////
  164. public:
  165. /**
  166. * Take the lock as a Reader.
  167. * This allows multiple reader access.
  168. */
  169. virtual void ReaderLock();
  170. /**
  171. * Unlock the Reader.
  172. */
  173. virtual void ReaderUnlock();
  174. /**
  175. * Take the lock as a Writer.
  176. * This allows only one thread access.
  177. */
  178. virtual void WriterLock();
  179. /**
  180. * Unlock the Writer.
  181. */
  182. virtual void WriterUnlock();
  183. };
  184. /**
  185. * Concrete derived class that implements a Reader/Writer lock
  186. * that favors the Writers. That is, with enough aggressive writers,
  187. * a Reader may starve.
  188. */
  189. class ReadWriteLockPreferWriter : public ReadWriteLock {
  190. /////////////////////////////////////////////////////////////////////////
  191. //
  192. // Public API
  193. //
  194. /////////////////////////////////////////////////////////////////////////
  195. public:
  196. /**
  197. * Our derived constructor.
  198. */
  199. ReadWriteLockPreferWriter();
  200. /**
  201. * Our derived destructor.
  202. */
  203. virtual ~ReadWriteLockPreferWriter();
  204. /**
  205. * Take the lock as a Reader.
  206. * This allows multiple reader access.
  207. */
  208. virtual void ReaderLock();
  209. /**
  210. * Unlock the Reader.
  211. */
  212. virtual void ReaderUnlock();
  213. /**
  214. * Take the lock as a Writer.
  215. * This allows only one thread access.
  216. */
  217. virtual void WriterLock();
  218. /**
  219. * Unlock the Writer.
  220. */
  221. virtual void WriterUnlock();
  222. /////////////////////////////////////////////////////////////////////////
  223. //
  224. // Private API
  225. // The internals of this wrapper class.
  226. //
  227. /////////////////////////////////////////////////////////////////////////
  228. private:
  229. /**
  230. * Number of Writers waiting for the Resource Lock, including any
  231. * current Writer already holdign it.
  232. */
  233. int WriteCount;
  234. /**
  235. * Protect WriteCount.
  236. */
  237. SemaphoreHandle_t WriteLock;
  238. /**
  239. * Lock to stop reader threads from starving a Writer.
  240. */
  241. SemaphoreHandle_t BlockReadersLock;
  242. };
  243. }
  244. #endif