You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
11 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: unixstl/synch/semaphore.hpp
  3. *
  4. * Purpose: Semaphore class, based on POSIX semaphore object.
  5. *
  6. * Created: 30th May 2006
  7. * Updated: 10th August 2009
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2006-2009, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file unixstl/synch/semaphore.hpp
  40. *
  41. * \brief [C++ only] Definition of unixstl::semaphore class
  42. * (\ref group__library__synch "Synchronisation" Library).
  43. */
  44. #ifndef UNIXSTL_INCL_UNIXSTL_SYNCH_HPP_SEMAPHORE
  45. #define UNIXSTL_INCL_UNIXSTL_SYNCH_HPP_SEMAPHORE
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define UNIXSTL_VER_UNIXSTL_SYNCH_HPP_SEMAPHORE_MAJOR 1
  48. # define UNIXSTL_VER_UNIXSTL_SYNCH_HPP_SEMAPHORE_MINOR 2
  49. # define UNIXSTL_VER_UNIXSTL_SYNCH_HPP_SEMAPHORE_REVISION 2
  50. # define UNIXSTL_VER_UNIXSTL_SYNCH_HPP_SEMAPHORE_EDIT 20
  51. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  52. /* /////////////////////////////////////////////////////////////////////////
  53. * Includes
  54. */
  55. #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
  56. # include <unixstl/unixstl.h>
  57. #endif /* !UNIXSTL_INCL_UNIXSTL_H_UNIXSTL */
  58. #ifndef STLSOFT_INCL_STLSOFT_SYNCH_HPP_CONCEPTS
  59. # include <stlsoft/synch/concepts.hpp>
  60. #endif /* !STLSOFT_INCL_STLSOFT_SYNCH_HPP_CONCEPTS */
  61. #ifndef UNIXSTL_INCL_UNIXSTL_SYNCH_ERROR_HPP_EXCEPTIONS
  62. # include <unixstl/synch/error/exceptions.hpp>
  63. #endif /* !UNIXSTL_INCL_UNIXSTL_SYNCH_ERROR_HPP_EXCEPTIONS */
  64. #ifndef STLSOFT_INCL_H_ERRNO
  65. # define STLSOFT_INCL_H_ERRNO
  66. # include <errno.h>
  67. #endif /* !STLSOFT_INCL_H_ERRNO */
  68. #ifndef STLSOFT_INCL_H_SEMAPHORE
  69. # define STLSOFT_INCL_H_SEMAPHORE
  70. # include <semaphore.h>
  71. #endif /* !STLSOFT_INCL_H_SEMAPHORE */
  72. /* /////////////////////////////////////////////////////////////////////////
  73. * Namespace
  74. */
  75. #ifndef _UNIXSTL_NO_NAMESPACE
  76. # if defined(_STLSOFT_NO_NAMESPACE) || \
  77. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  78. /* There is no stlsoft namespace, so must define ::unixstl */
  79. namespace unixstl
  80. {
  81. # else
  82. /* Define stlsoft::unixstl_project */
  83. namespace stlsoft
  84. {
  85. namespace unixstl_project
  86. {
  87. # endif /* _STLSOFT_NO_NAMESPACE */
  88. #endif /* !_UNIXSTL_NO_NAMESPACE */
  89. /* /////////////////////////////////////////////////////////////////////////
  90. * Classes
  91. */
  92. // class semaphore
  93. /** \brief This class acts as an semaphore based on the POSIX
  94. * semaphore object
  95. *
  96. * \ingroup group__library__synch
  97. */
  98. class semaphore
  99. : public stlsoft_ns_qual(critical_section)< STLSOFT_CRITICAL_SECTION_ISNOT_RECURSIVE
  100. , STLSOFT_CRITICAL_SECTION_IS_TRYABLE
  101. >
  102. , public stlsoft_ns_qual(synchronisable_object_tag)
  103. {
  104. /// \name Member Types
  105. /// @{
  106. public:
  107. typedef semaphore class_type;
  108. typedef sem_t* handle_type;
  109. typedef us_bool_t bool_type;
  110. typedef us_size_t count_type;
  111. typedef sem_t* resource_type;
  112. /// @}
  113. /// \name Member Constants
  114. /// @{
  115. public:
  116. enum
  117. {
  118. maxCountValue = _POSIX_SEM_VALUE_MAX // Borrowed from PThreads-win32
  119. };
  120. /// @}
  121. /// \name Construction
  122. /// @{
  123. public:
  124. /// \brief Conversion constructor
  125. semaphore(handle_type sem, bool_type bTakeOwnership)
  126. : m_sem(sem)
  127. , m_bOwnHandle(bTakeOwnership)
  128. {
  129. UNIXSTL_ASSERT(NULL != sem);
  130. }
  131. /// \brief Creates an instance of the semaphore
  132. ss_explicit_k semaphore(count_type initialCount, bool_type bInterProcessShared = false)
  133. : m_sem(create_semaphore_(&m_semInternal, initialCount, bInterProcessShared))
  134. , m_bOwnHandle(true)
  135. {}
  136. /// \brief Destroys an instance of the semaphore
  137. ~semaphore() stlsoft_throw_0()
  138. {
  139. if( NULL != m_sem &&
  140. m_bOwnHandle)
  141. {
  142. ::sem_destroy(m_sem);
  143. }
  144. }
  145. #if 0
  146. void close() stlsoft_throw_0()
  147. {
  148. if( NULL != m_sem &&
  149. m_bOwnHandle)
  150. {
  151. ::sem_destroy(m_sem);
  152. m_sem = NULL;
  153. }
  154. }
  155. #endif /* 0 */
  156. /// @}
  157. /// \name Operations
  158. /// @{
  159. public:
  160. /// \brief Acquires a lock on the semaphore, pending the thread until the lock is aquired
  161. void lock()
  162. {
  163. UNIXSTL_ASSERT(NULL != m_sem);
  164. if(::sem_wait(m_sem) < 0)
  165. {
  166. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  167. STLSOFT_THROW_X(synchronisation_exception("semaphore wait failed", errno));
  168. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  169. }
  170. }
  171. /// \brief Attempts to lock the semaphore
  172. ///
  173. /// \return <b>true</b> if the semaphore was aquired, or <b>false</b> if not
  174. bool_type try_lock()
  175. {
  176. UNIXSTL_ASSERT(NULL != m_sem);
  177. int res = ::sem_trywait(m_sem);
  178. if(0 == res)
  179. {
  180. return true;
  181. }
  182. else
  183. {
  184. if(EAGAIN != res)
  185. {
  186. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  187. STLSOFT_THROW_X(synchronisation_exception("semaphore wait failed", errno));
  188. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  189. }
  190. }
  191. return false;
  192. }
  193. /// \brief Releases an aquired lock on the semaphore, increasing the
  194. /// semaphore's counter by one.
  195. void unlock()
  196. {
  197. UNIXSTL_ASSERT(NULL != m_sem);
  198. if(::sem_post(m_sem) < 0)
  199. {
  200. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  201. STLSOFT_THROW_X(synchronisation_exception("semaphore release failed", errno));
  202. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  203. }
  204. }
  205. /// @}
  206. /// \name Accessors
  207. /// @{
  208. public:
  209. /// \brief The underlying kernel object handle
  210. handle_type handle() stlsoft_throw_0()
  211. {
  212. return m_sem;
  213. }
  214. /// \brief The underlying kernel object handle
  215. handle_type get() stlsoft_throw_0()
  216. {
  217. return m_sem;
  218. }
  219. /// @}
  220. // Implementation
  221. private:
  222. static handle_type create_semaphore_(sem_t* internal, count_type initialCount, bool_type bInterProcessShared)
  223. {
  224. UNIXSTL_ASSERT(initialCount <= maxCountValue);
  225. handle_type sem;
  226. if(::sem_init(internal, bInterProcessShared, initialCount) < 0)
  227. {
  228. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  229. STLSOFT_THROW_X(synchronisation_exception("Failed to create kernel semaphore object", errno));
  230. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  231. sem = NULL;
  232. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  233. }
  234. else
  235. {
  236. sem = internal;
  237. }
  238. return sem;
  239. }
  240. // Members
  241. private:
  242. sem_t m_semInternal; // The actual object if internally initialised
  243. handle_type m_sem; // Handle to the underlying semaphore object
  244. const bool_type m_bOwnHandle; // Does the instance own the handle?
  245. // Not to be implemented
  246. private:
  247. semaphore(class_type const& rhs);
  248. semaphore& operator =(class_type const& rhs);
  249. };
  250. /* /////////////////////////////////////////////////////////////////////////
  251. * Shims
  252. */
  253. #ifndef _UNIXSTL_NO_NAMESPACE
  254. # if defined(_STLSOFT_NO_NAMESPACE) || \
  255. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  256. } // namespace unixstl
  257. # else
  258. } // namespace unixstl_project
  259. # endif /* _STLSOFT_NO_NAMESPACE */
  260. #endif /* !_UNIXSTL_NO_NAMESPACE */
  261. /** \brief This \ref group__concept__shims "control shim" aquires a lock on the given semaphore
  262. *
  263. * \ingroup group__concept__shim__synchronisation_control
  264. *
  265. * \param sem The semaphore on which to aquire the lock.
  266. */
  267. inline void lock_instance(unixstl_ns_qual(semaphore) &sem)
  268. {
  269. sem.lock();
  270. }
  271. /** \brief This \ref group__concept__shims "control shim" releases a lock on the given semaphore
  272. *
  273. * \ingroup group__concept__shim__synchronisation_control
  274. *
  275. * \param sem The semaphore on which to release the lock
  276. */
  277. inline void unlock_instance(unixstl_ns_qual(semaphore) &sem)
  278. {
  279. sem.unlock();
  280. }
  281. #ifndef _UNIXSTL_NO_NAMESPACE
  282. # if defined(_STLSOFT_NO_NAMESPACE) || \
  283. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  284. namespace unixstl {
  285. # else
  286. namespace unixstl_project {
  287. # if defined(STLSOFT_COMPILER_IS_BORLAND)
  288. using ::stlsoft::lock_instance;
  289. using ::stlsoft::unlock_instance;
  290. # endif /* compiler */
  291. # endif /* _STLSOFT_NO_NAMESPACE */
  292. #endif /* !_UNIXSTL_NO_NAMESPACE */
  293. /* /////////////////////////////////////////////////////////////////////////
  294. * lock_traits
  295. */
  296. // class lock_traits
  297. /** \brief Traits for the semaphore class
  298. *
  299. * \ingroup group__library__synch
  300. */
  301. struct semaphore_lock_traits
  302. {
  303. public:
  304. /// The lockable type
  305. typedef semaphore lock_type;
  306. typedef semaphore_lock_traits class_type;
  307. // Operations
  308. public:
  309. /// Lock the given semaphore instance
  310. static void lock(semaphore &c)
  311. {
  312. lock_instance(c);
  313. }
  314. /// Unlock the given semaphore instance
  315. static void unlock(semaphore &c)
  316. {
  317. unlock_instance(c);
  318. }
  319. };
  320. ////////////////////////////////////////////////////////////////////////////
  321. // Unit-testing
  322. #ifdef STLSOFT_UNITTEST
  323. # include "./unittest/semaphore_unittest_.h"
  324. #endif /* STLSOFT_UNITTEST */
  325. /* ////////////////////////////////////////////////////////////////////// */
  326. #ifndef _UNIXSTL_NO_NAMESPACE
  327. # if defined(_STLSOFT_NO_NAMESPACE) || \
  328. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  329. } // namespace unixstl
  330. # else
  331. } // namespace unixstl_project
  332. } // namespace stlsoft
  333. # endif /* _STLSOFT_NO_NAMESPACE */
  334. #endif /* !_UNIXSTL_NO_NAMESPACE */
  335. /* ////////////////////////////////////////////////////////////////////// */
  336. #endif /* !UNIXSTL_INCL_UNIXSTL_SYNCH_HPP_SEMAPHORE */
  337. /* ///////////////////////////// end of file //////////////////////////// */