semaphore_wrapper.hpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // See http://www.boost.org/libs/interprocess for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. #ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
  11. #define BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
  12. #ifndef BOOST_CONFIG_HPP
  13. # include <boost/config.hpp>
  14. #endif
  15. #
  16. #if defined(BOOST_HAS_PRAGMA_ONCE)
  17. # pragma once
  18. #endif
  19. #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
  20. #include <boost/interprocess/exceptions.hpp>
  21. #include <boost/interprocess/creation_tags.hpp>
  22. #include <boost/interprocess/detail/os_file_functions.hpp>
  23. #include <boost/interprocess/detail/shared_dir_helpers.hpp>
  24. #include <boost/interprocess/permissions.hpp>
  25. #include <fcntl.h> //O_CREAT, O_*...
  26. #include <unistd.h> //close
  27. #include <string> //std::string
  28. #include <semaphore.h> //sem_* family, SEM_VALUE_MAX
  29. #include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
  30. #include <boost/assert.hpp>
  31. #ifdef SEM_FAILED
  32. #define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(SEM_FAILED))
  33. #else
  34. #define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(-1))
  35. #endif
  36. #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
  37. #include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
  38. #else
  39. #include <boost/interprocess/detail/os_thread_functions.hpp>
  40. #include <boost/interprocess/sync/detail/locks.hpp>
  41. #include <boost/interprocess/sync/detail/common_algorithms.hpp>
  42. #endif
  43. namespace boost {
  44. namespace interprocess {
  45. namespace ipcdetail {
  46. #ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
  47. inline bool semaphore_open
  48. (sem_t *&handle, create_enum_t type, const char *origname,
  49. unsigned int count = 0, const permissions &perm = permissions())
  50. {
  51. std::string name;
  52. #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
  53. add_leading_slash(origname, name);
  54. #else
  55. create_shared_dir_cleaning_old_and_get_filepath(origname, name);
  56. #endif
  57. //Create new mapping
  58. int oflag = 0;
  59. switch(type){
  60. case DoOpen:
  61. {
  62. //No addition
  63. handle = ::sem_open(name.c_str(), oflag);
  64. }
  65. break;
  66. case DoOpenOrCreate:
  67. case DoCreate:
  68. {
  69. while(1){
  70. oflag = (O_CREAT | O_EXCL);
  71. handle = ::sem_open(name.c_str(), oflag, perm.get_permissions(), count);
  72. if(handle != BOOST_INTERPROCESS_POSIX_SEM_FAILED){
  73. //We can't change semaphore permissions!
  74. //::fchmod(handle, perm.get_permissions());
  75. break;
  76. }
  77. else if(errno == EEXIST && type == DoOpenOrCreate){
  78. oflag = 0;
  79. if( (handle = ::sem_open(name.c_str(), oflag)) != BOOST_INTERPROCESS_POSIX_SEM_FAILED
  80. || (errno != ENOENT) ){
  81. break;
  82. }
  83. }
  84. else{
  85. break;
  86. }
  87. }
  88. }
  89. break;
  90. default:
  91. {
  92. error_info err(other_error);
  93. throw interprocess_exception(err);
  94. }
  95. }
  96. //Check for error
  97. if(handle == BOOST_INTERPROCESS_POSIX_SEM_FAILED){
  98. throw interprocess_exception(error_info(errno));
  99. }
  100. return true;
  101. }
  102. inline void semaphore_close(sem_t *handle)
  103. {
  104. int ret = sem_close(handle);
  105. if(ret != 0){
  106. BOOST_ASSERT(0);
  107. }
  108. }
  109. inline bool semaphore_unlink(const char *semname)
  110. {
  111. try{
  112. std::string sem_str;
  113. #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
  114. add_leading_slash(semname, sem_str);
  115. #else
  116. shared_filepath(semname, sem_str);
  117. #endif
  118. return 0 == sem_unlink(sem_str.c_str());
  119. }
  120. catch(...){
  121. return false;
  122. }
  123. }
  124. #endif //BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
  125. #ifdef BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES
  126. inline void semaphore_init(sem_t *handle, unsigned int initialCount)
  127. {
  128. int ret = sem_init(handle, 1, initialCount);
  129. //According to SUSV3 version 2003 edition, the return value of a successful
  130. //sem_init call is not defined, but -1 is returned on failure.
  131. //In the future, a successful call might be required to return 0.
  132. if(ret == -1){
  133. error_info err = system_error_code();
  134. throw interprocess_exception(err);
  135. }
  136. }
  137. inline void semaphore_destroy(sem_t *handle)
  138. {
  139. int ret = sem_destroy(handle);
  140. if(ret != 0){
  141. BOOST_ASSERT(0);
  142. }
  143. }
  144. #endif //BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES
  145. inline void semaphore_post(sem_t *handle)
  146. {
  147. int ret = sem_post(handle);
  148. if(ret != 0){
  149. error_info err = system_error_code();
  150. throw interprocess_exception(err);
  151. }
  152. }
  153. inline void semaphore_wait(sem_t *handle)
  154. {
  155. int ret = sem_wait(handle);
  156. if(ret != 0){
  157. error_info err = system_error_code();
  158. throw interprocess_exception(err);
  159. }
  160. }
  161. inline bool semaphore_try_wait(sem_t *handle)
  162. {
  163. int res = sem_trywait(handle);
  164. if(res == 0)
  165. return true;
  166. if(system_error_code() == EAGAIN){
  167. return false;
  168. }
  169. error_info err = system_error_code();
  170. throw interprocess_exception(err);
  171. }
  172. #ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
  173. struct semaphore_wrapper_try_wrapper
  174. {
  175. explicit semaphore_wrapper_try_wrapper(sem_t *handle)
  176. : m_handle(handle)
  177. {}
  178. void wait()
  179. { semaphore_wait(m_handle); }
  180. bool try_wait()
  181. { return semaphore_try_wait(m_handle); }
  182. private:
  183. sem_t *m_handle;
  184. };
  185. #endif
  186. inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime &abs_time)
  187. {
  188. #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
  189. //Posix does not support infinity absolute time so handle it here
  190. if(abs_time == boost::posix_time::pos_infin){
  191. semaphore_wait(handle);
  192. return true;
  193. }
  194. timespec tspec = ptime_to_timespec(abs_time);
  195. for (;;){
  196. int res = sem_timedwait(handle, &tspec);
  197. if(res == 0)
  198. return true;
  199. if (res > 0){
  200. //buggy glibc, copy the returned error code to errno
  201. errno = res;
  202. }
  203. if(system_error_code() == ETIMEDOUT){
  204. return false;
  205. }
  206. error_info err = system_error_code();
  207. throw interprocess_exception(err);
  208. }
  209. return false;
  210. #else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
  211. semaphore_wrapper_try_wrapper swtw(handle);
  212. ipcdetail::lock_to_wait<semaphore_wrapper_try_wrapper> lw(swtw);
  213. return ipcdetail::try_based_timed_lock(lw, abs_time);
  214. #endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
  215. }
  216. } //namespace ipcdetail {
  217. } //namespace interprocess {
  218. } //namespace boost {
  219. #endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP