semaphore_pos.cpp
Go to the documentation of this file.
1 
9 /*****************************************************************************
10 ** Includes
11 *****************************************************************************/
12 
13 #include "../../include/ecl/ipc/semaphore_pos.hpp"
14 
15 #ifdef ECL_HAS_POSIX_SEMAPHORES
16 
17 #include <errno.h>
18 #include <sstream>
19 #include <ecl/errors/handlers.hpp>
22 
23 /*****************************************************************************
24 ** Namespaces
25 *****************************************************************************/
26 
27 namespace ecl {
28 
29 /*****************************************************************************
30 ** Using
31 *****************************************************************************/
32 
33 using std::string;
34 using std::ostringstream;
35 
36 /*****************************************************************************
37 ** Implementation [Semaphore]
38 *****************************************************************************/
39 
40 Semaphore::Semaphore() throw(StandardException) {
41  // Never use this constructor
42  throw StandardException(LOC, RaiiError);
43 }
44 
45 Semaphore::Semaphore(const std::string& string_id) ecl_assert_throw_decl(StandardException):
46  name(string("/"+string_id)),
47  semaphore(NULL)
48 {
49  /*********************
50  * Open Flags
51  *********************/
52  /*
53  * O_CREAT : it will try and create a semaphore or just open if it already exists
54  * O_EXCL : when used with O_CREAT fails to open if the semaphore already exists.
55  *
56  * Other flags are unnecessary.
57  */
58  static const int open_flags = O_CREAT;
59  /*********************
60  * Permissions
61  *********************/
62  /*
63  * Permissions. Must be specified when O_CREAT is used, otherwise it is ignored. It
64  * is combined with the process umask (permissions & ~umask).
65  * S_IRWXU [00700] - read, write & exec by user
66  * S_IRUSR [00400] - read by the user who owns it
67  * S_IWUSR [00200] - write by user
68  * S_IXUSR [00100] - exec by user
69  * S_IRWXG [00070] - read, write & exec by group
70  * S_IRGRP [00040] - read by group
71  * S_IWGRP [00020] - write by group
72  * S_IXGRP [00010] - exe by group
73  * S_IRWXG [00007] - read, write & exec by other
74  * S_IROTH [00004] - read by other
75  * S_IWOTH [00002] - write by other
76  * S_IXOTH [00001] - exe by other
77  *
78  * Semaphores just have access, or they do not (p.137 of the posix bible). Just
79  * set rwx on whichever subset of users applies. As we're not worried about
80  * security here, just open them up.
81  */
82  static const int permissions = S_IRWXU|S_IRWXG|S_IRWXO;
83  /*
84  * The initial value of the semaphore. For mutex style semaphores, set the
85  * initial value to be unlocked.
86  */
87  static const int initial_value_unlocked = 1;
88 
89  /*********************
90  ** Open
91  **********************/
92  semaphore = sem_open(name.c_str(),open_flags,permissions,initial_value_unlocked);
93  ecl_assert_throw(semaphore != SEM_FAILED, ipc::openSemaphoreException(LOC));
94 }
95 
96 Semaphore::~Semaphore()
97 {
98  // Should check the error, but only fails if the semaphore is invalid (checked by constructor).
99  sem_close(semaphore);
100  // Should check the error, but only fails with noncritical errors.
101  sem_unlink(name.c_str());
102 }
103 
104 void Semaphore::lock()
105 {
106  sem_wait(semaphore);
107 }
108 
109 int Semaphore::count()
110 {
111  // Should check the error, but only fails if the semaphore is invalid (checked by constructor).
112  int semaphore_count;
113  sem_getvalue(semaphore,&semaphore_count);
114  return semaphore_count;
115 }
116 
117 void Semaphore::unlock()
118 {
119  // Should check the error, but only fails if the semaphore is invalid (checked by constructor).
120  // The other error is an overflow error, which is handled by constraining our count to 1.
121  if ( count() == 1 ) { // Already unlocked
122  return;
123  } else {
124  sem_post(semaphore);
125  }
126 }
127 
128 bool Semaphore::trylock()
129 {
130  // 0 is a success
131  if ( sem_trywait( semaphore ) == 0 ) {
132  return true;
133  } else {
134  // Should check errno = EAGAIN for implication that a locked semaphore caused it to fail
135  // and not something else
136  return false;
137  }
138 }
139 
140 bool Semaphore::trylock( const Duration &timeout ) ecl_debug_throw_decl(StandardException) {
141 
142  #if defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS - 200112L) >= 0L
143  long tnsec;
144  timespec ctime;
145 
146  if ( epoch_time(ctime).flag() != NoError ) { return false; }
147 
148  ctime.tv_sec += timeout.sec();
149 
150  tnsec = ctime.tv_nsec + timeout.nsec();
151  if(tnsec >= 999999999 ) { ctime.tv_sec += 1; }
152  tnsec %= 1000000000;
153  ctime.tv_nsec = tnsec;
154 
155  // We already guarantee timeout is the right structure, so no
156  // need to check for EINVAL, other errors should be almost
157  // irrelevant for us too.
158  int result = sem_timedwait( semaphore, &ctime );
159  if ( result != 0 ) {
160  if ( errno == ETIMEDOUT ) {
161  // The timeout kicked in
162  return false;
163  } else {
164  ecl_debug_throw( ipc::tryLockSemaphoreException(LOC));
165  // either a signal interrupt EINTR
166  // or a blocking (when does this occur? EAGAIN
167  return false;
168  }
169  }
170  #else
171  return trylock(); // fallback to standard trylock
172  #endif
173  return true;
174 }
175 
176 /*****************************************************************************
177 ** Exception Handlers
178 *****************************************************************************/
179 
180 #ifdef ECL_HAS_EXCEPTIONS
181 
182 namespace ipc {
183 
184 ecl::StandardException openSemaphoreException(const char* loc) {
185  int error_result = errno;
186  switch ( error_result ) {
187  case ( EACCES ) : {
188  return StandardException(LOC,PermissionsError,"The semaphore exists, but permission to open has been denied.");
189  }
190  case ( EEXIST ) : {
191  return StandardException(LOC,PermissionsError,"The semaphore already exists, so your request to explicitly create was denied.");
192  }
193  case ( ENOENT ) : {
194  return StandardException(LOC,ConfigurationError,"The semaphore requested doesn't already exist (you specifically requested it to just open, not create).");
195  }
196  case ( ENOMEM ) : {
197  return StandardException(LOC,MemoryError,"Insufficient memory.");
198  }
199  case ( EINVAL ) : {
200  return StandardException(LOC,InvalidArgError,"Name was empty (i.e. '/'). Can also be the maximum number of semaphores has already been exceeded.");
201  }
202  case ( EMFILE ) : {
203  return StandardException(LOC,OutOfResourcesError,"This process has already exceeded the number of files/pseudofiles it is permitted to open.");
204  }
205  case ( ENFILE ) : {
206  return StandardException(LOC,OutOfResourcesError,"This system has already exceeded the number of files/pseudofiles it is permitted to open.");
207  }
208  case ( ENAMETOOLONG ) : {
209  return StandardException(LOC,InvalidArgError,"The semaphore name was too long.");
210  }
211  default :
212  {
213  ostringstream ostream;
214  ostream << "Unknown posix error " << error_result << ": " << strerror(error_result) << ".";
215  return StandardException(loc, UnknownError, ostream.str());
216  }
217  }
218 }
219 
220 ecl::StandardException tryLockSemaphoreException(const char* loc) {
221  int error_result = errno;
222  switch ( error_result ) {
223  case ( EINTR ) : {
224  return StandardException(LOC,InterruptedError,"Waiting for the semaphore lock was interrupted by a system signal.");
225  }
226  case ( EINVAL ) : {
227  return StandardException(LOC,InvalidArgError,"The semaphore was invalid or the timeout structure specified was invalid.");
228  }
229  case ( EAGAIN ) : {
230  return StandardException(LOC,BlockingError,"The waiting operation could not be performed without blocking???");
231  }
232  default :
233  {
234  ostringstream ostream;
235  ostream << "Posix error " << error_result << ": " << strerror(error_result) << ".";
236  return StandardException(loc, UnknownError, ostream.str());
237  }
238  }
239 }
240 
241 } // namespace ipc
242 
243 #endif /* ECL_HAS_EXCEPTIONS */
244 
245 }; // namespace ecl
246 
247 #endif /* ECL_HAS_POSIX_SEMAPHORES */
Embedded control libraries.
InterruptedError
PermissionsError
InvalidArgError
UnknownError
#define ecl_assert_throw(expression, exception)
ConfigurationError
BlockingError
OutOfResourcesError
#define ecl_assert_throw_decl(exception)
TimeStamp Duration
#define ecl_debug_throw_decl(exception)
#define ecl_debug_throw(exception)
MemoryError


ecl_ipc
Author(s): Daniel Stonier
autogenerated on Mon Jun 10 2019 13:08:17