semaphore_wrapper.hpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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. #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
  13. #include <boost/interprocess/exceptions.hpp>
  14. #include <boost/interprocess/creation_tags.hpp>
  15. #include <boost/interprocess/detail/os_file_functions.hpp>
  16. #include <boost/interprocess/detail/tmp_dir_helpers.hpp>
  17. #include <boost/interprocess/permissions.hpp>
  18. #include <fcntl.h> //O_CREAT, O_*...
  19. #include <unistd.h> //close
  20. #include <string> //std::string
  21. #include <semaphore.h> //sem_* family, SEM_VALUE_MAX
  22. #include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
  23. #include <boost/assert.hpp>
  24. #ifdef SEM_FAILED
  25. #define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(SEM_FAILED))
  26. #else
  27. #define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(-1))
  28. #endif
  29. #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
  30. #include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
  31. #else
  32. #include <boost/interprocess/detail/os_thread_functions.hpp>
  33. #include <boost/interprocess/sync/spin/wait.hpp>
  34. #endif
  35. namespace boost {
  36. namespace interprocess {
  37. namespace ipcdetail {
  38. inline bool semaphore_open
  39. (sem_t *&handle, create_enum_t type, const char *origname,
  40. unsigned int count = 0, const permissions &perm = permissions())
  41. {
  42. std::string name;
  43. #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
  44. add_leading_slash(origname, name);
  45. #else
  46. create_tmp_and_clean_old_and_get_filename(origname, name);
  47. #endif
  48. //Create new mapping
  49. int oflag = 0;
  50. switch(type){
  51. case DoOpen:
  52. {
  53. //No addition
  54. handle = ::sem_open(name.c_str(), oflag);
  55. }
  56. break;
  57. case DoOpenOrCreate:
  58. case DoCreate:
  59. {
  60. while(1){
  61. oflag = (O_CREAT | O_EXCL);
  62. handle = ::sem_open(name.c_str(), oflag, perm.get_permissions(), count);
  63. if(handle != BOOST_INTERPROCESS_POSIX_SEM_FAILED){
  64. //We can't change semaphore permissions!
  65. //::fchmod(handle, perm.get_permissions());
  66. break;
  67. }
  68. else if(errno == EEXIST && type == DoOpenOrCreate){
  69. oflag = 0;
  70. if( (handle = ::sem_open(name.c_str(), oflag)) != BOOST_INTERPROCESS_POSIX_SEM_FAILED
  71. || (errno != ENOENT) ){
  72. break;
  73. }
  74. }
  75. else{
  76. break;
  77. }
  78. }
  79. }
  80. break;
  81. default:
  82. {
  83. error_info err(other_error);
  84. throw interprocess_exception(err);
  85. }
  86. }
  87. //Check for error
  88. if(handle == BOOST_INTERPROCESS_POSIX_SEM_FAILED){
  89. throw interprocess_exception(error_info(errno));
  90. }
  91. return true;
  92. }
  93. inline void semaphore_close(sem_t *handle)
  94. {
  95. int ret = sem_close(handle);
  96. if(ret != 0){
  97. BOOST_ASSERT(0);
  98. }
  99. }
  100. inline bool semaphore_unlink(const char *semname)
  101. {
  102. try{
  103. std::string sem_str;
  104. #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
  105. add_leading_slash(semname, sem_str);
  106. #else
  107. tmp_filename(semname, sem_str);
  108. #endif
  109. return 0 == sem_unlink(sem_str.c_str());
  110. }
  111. catch(...){
  112. return false;
  113. }
  114. }
  115. inline void semaphore_init(sem_t *handle, unsigned int initialCount)
  116. {
  117. int ret = sem_init(handle, 1, initialCount);
  118. //According to SUSV3 version 2003 edition, the return value of a successful
  119. //sem_init call is not defined, but -1 is returned on failure.
  120. //In the future, a successful call might be required to return 0.
  121. if(ret == -1){
  122. throw interprocess_exception(system_error_code());
  123. }
  124. }
  125. inline void semaphore_destroy(sem_t *handle)
  126. {
  127. int ret = sem_destroy(handle);
  128. if(ret != 0){
  129. BOOST_ASSERT(0);
  130. }
  131. }
  132. inline void semaphore_post(sem_t *handle)
  133. {
  134. int ret = sem_post(handle);
  135. if(ret != 0){
  136. throw interprocess_exception(system_error_code());
  137. }
  138. }
  139. inline void semaphore_wait(sem_t *handle)
  140. {
  141. int ret = sem_wait(handle);
  142. if(ret != 0){
  143. throw interprocess_exception(system_error_code());
  144. }
  145. }
  146. inline bool semaphore_try_wait(sem_t *handle)
  147. {
  148. int res = sem_trywait(handle);
  149. if(res == 0)
  150. return true;
  151. if(system_error_code() == EAGAIN){
  152. return false;
  153. }
  154. throw interprocess_exception(system_error_code());
  155. return false;
  156. }
  157. inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime &abs_time)
  158. {
  159. if(abs_time == boost::posix_time::pos_infin){
  160. semaphore_wait(handle);
  161. return true;
  162. }
  163. #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
  164. timespec tspec = ptime_to_timespec(abs_time);
  165. for (;;){
  166. int res = sem_timedwait(handle, &tspec);
  167. if(res == 0)
  168. return true;
  169. if (res > 0){
  170. //buggy glibc, copy the returned error code to errno
  171. errno = res;
  172. }
  173. if(system_error_code() == ETIMEDOUT){
  174. return false;
  175. }
  176. throw interprocess_exception(system_error_code());
  177. }
  178. return false;
  179. #else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
  180. boost::posix_time::ptime now;
  181. spin_wait swait;
  182. do{
  183. if(semaphore_try_wait(handle))
  184. return true;
  185. swait.yield();
  186. }while((now = microsec_clock::universal_time()) < abs_time);
  187. return false;
  188. #endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
  189. }
  190. } //namespace ipcdetail {
  191. } //namespace interprocess {
  192. } //namespace boost {
  193. #endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP