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