semaphore_pos.cpp
Go to the documentation of this file.
00001 
00009 /*****************************************************************************
00010 ** Includes
00011 *****************************************************************************/
00012 
00013 #include "../../include/ecl/ipc/semaphore_pos.hpp"
00014 
00015 #ifdef ECL_HAS_POSIX_SEMAPHORES
00016 
00017 #include <errno.h>
00018 #include <sstream>
00019 #include <ecl/errors/handlers.hpp>
00020 #include <ecl/exceptions/standard_exception.hpp>
00021 #include <ecl/time_lite/functions.hpp>
00022 
00023 /*****************************************************************************
00024 ** Namespaces
00025 *****************************************************************************/
00026 
00027 namespace ecl {
00028 
00029 /*****************************************************************************
00030 ** Using
00031 *****************************************************************************/
00032 
00033 using std::string;
00034 using std::ostringstream;
00035 
00036 /*****************************************************************************
00037 ** Implementation [Semaphore]
00038 *****************************************************************************/
00039 
00040 Semaphore::Semaphore() throw(StandardException) {
00041         // Never use this constructor
00042         throw StandardException(LOC, RaiiError);
00043 }
00044 
00045 Semaphore::Semaphore(const std::string& string_id) ecl_assert_throw_decl(StandardException):
00046         name(string("/"+string_id)),
00047         semaphore(NULL)
00048 {
00049     /*********************
00050      * Open Flags
00051      *********************/
00052     /*
00053      * O_CREAT    : it will try and create a semaphore or just open if it already exists
00054      * O_EXCL     : when used with O_CREAT fails to open if the semaphore already exists.
00055      *
00056      * Other flags are unnecessary.
00057      */
00058     static const int open_flags = O_CREAT;
00059     /*********************
00060      * Permissions
00061      *********************/
00062     /*
00063      * Permissions. Must be specified when O_CREAT is used, otherwise it is ignored. It
00064      * is combined with the process umask (permissions & ~umask).
00065      * S_IRWXU [00700] - read, write & exec by user
00066      * S_IRUSR [00400] - read by the user who owns it
00067      * S_IWUSR [00200] - write by user
00068      * S_IXUSR [00100] - exec by user
00069      * S_IRWXG [00070] - read, write & exec by group
00070      * S_IRGRP [00040] - read by group
00071      * S_IWGRP [00020] - write by group
00072      * S_IXGRP [00010] - exe by group
00073      * S_IRWXG [00007] - read, write & exec by other
00074      * S_IROTH [00004] - read by other
00075      * S_IWOTH [00002] - write by other
00076      * S_IXOTH [00001] - exe by other
00077      *
00078      * Semaphores just have access, or they do not (p.137 of the posix bible). Just
00079      * set rwx on whichever subset of users applies. As we're not worried about
00080      * security here, just open them up.
00081     */
00082     static const int permissions = S_IRWXU|S_IRWXG|S_IRWXO;
00083     /*
00084      * The initial value of the semaphore. For mutex style semaphores, set the
00085      * initial value to be unlocked.
00086      */
00087     static const int initial_value_unlocked = 1;
00088 
00089     /*********************
00090     ** Open
00091     **********************/
00092     semaphore = sem_open(name.c_str(),open_flags,permissions,initial_value_unlocked);
00093     ecl_assert_throw(semaphore != SEM_FAILED, ipc::openSemaphoreException(LOC));
00094 }
00095 
00096 Semaphore::~Semaphore()
00097 {
00098         // Should check the error, but only fails if the semaphore is invalid (checked by constructor).
00099     sem_close(semaphore);
00100         // Should check the error, but only fails with noncritical errors.
00101     sem_unlink(name.c_str());
00102 }
00103 
00104 void Semaphore::lock()
00105 {
00106         sem_wait(semaphore);
00107 }
00108 
00109 int Semaphore::count()
00110 {
00111         // Should check the error, but only fails if the semaphore is invalid (checked by constructor).
00112     int semaphore_count;
00113     sem_getvalue(semaphore,&semaphore_count);
00114     return semaphore_count;
00115 }
00116 
00117 void Semaphore::unlock()
00118 {
00119         // Should check the error, but only fails if the semaphore is invalid (checked by constructor).
00120         // The other error is an overflow error, which is handled by constraining our count to 1.
00121     if ( count() == 1 ) { // Already unlocked
00122         return;
00123     } else {
00124         sem_post(semaphore);
00125     }
00126 }
00127 
00128 bool Semaphore::trylock()
00129 {
00130         // 0 is a success
00131         if (  sem_trywait( semaphore ) == 0 ) {
00132                 return true;
00133         } else {
00134                 // Should check errno = EAGAIN for implication that a locked semaphore caused it to fail
00135                 // and not something else
00136                 return false;
00137         }
00138 }
00139 
00140 bool Semaphore::trylock( const Duration &timeout ) ecl_debug_throw_decl(StandardException) {
00141 
00142     #if defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS - 200112L) >= 0L
00143                 long tnsec;
00144                 timespec ctime;
00145 
00146                 if ( epoch_time(ctime).flag() != NoError ) { return false; }
00147 
00148                 ctime.tv_sec += timeout.sec();
00149 
00150                 tnsec = ctime.tv_nsec + timeout.nsec();
00151                 if(tnsec >=  999999999 ) { ctime.tv_sec += 1; }
00152                 tnsec %= 1000000000;
00153                 ctime.tv_nsec = tnsec;
00154 
00155                 // We already guarantee timeout is the right structure, so no
00156                 // need to check for EINVAL, other errors should be almost
00157                 // irrelevant for us too.
00158                 int result = sem_timedwait( semaphore, &ctime );
00159                 if ( result != 0 ) {
00160                         if ( errno == ETIMEDOUT ) {
00161                                 // The timeout kicked in
00162                                 return false;
00163                         } else {
00164                                 ecl_debug_throw( ipc::tryLockSemaphoreException(LOC));
00165                                 // either a signal interrupt EINTR
00166                                 // or a blocking (when does this occur? EAGAIN
00167                                 return false;
00168                         }
00169                 }
00170         #else
00171                 return trylock(); // fallback to standard trylock
00172         #endif
00173         return true;
00174 }
00175 
00176 /*****************************************************************************
00177 ** Exception Handlers
00178 *****************************************************************************/
00179 
00180 #ifdef ECL_HAS_EXCEPTIONS
00181 
00182 namespace ipc {
00183 
00184 ecl::StandardException openSemaphoreException(const char* loc) {
00185         int error_result = errno;
00186     switch ( error_result ) {
00187         case ( EACCES ) : {
00188             return StandardException(LOC,PermissionsError,"The semaphore exists, but permission to open has been denied.");
00189         }
00190         case ( EEXIST ) : {
00191             return StandardException(LOC,PermissionsError,"The semaphore already exists, so your request to explicitly create was denied.");
00192         }
00193         case ( ENOENT ) : {
00194             return StandardException(LOC,ConfigurationError,"The semaphore requested doesn't already exist (you specifically requested it to just open, not create).");
00195         }
00196         case ( ENOMEM ) : {
00197             return StandardException(LOC,MemoryError,"Insufficient memory.");
00198         }
00199         case ( EINVAL ) : {
00200             return StandardException(LOC,InvalidArgError,"Name was empty (i.e. '/'). Can also be the maximum number of semaphores has already been exceeded.");
00201         }
00202         case ( EMFILE ) : {
00203                 return StandardException(LOC,OutOfResourcesError,"This process has already exceeded the number of files/pseudofiles it is permitted to open.");
00204                 }
00205         case ( ENFILE ) : {
00206                 return StandardException(LOC,OutOfResourcesError,"This system has already exceeded the number of files/pseudofiles it is permitted to open.");
00207                 }
00208         case ( ENAMETOOLONG ) : {
00209                 return StandardException(LOC,InvalidArgError,"The semaphore name was too long.");
00210                 }
00211                 default         :
00212                 {
00213                         ostringstream ostream;
00214                         ostream << "Unknown posix error " << error_result << ": " << strerror(error_result) << ".";
00215                         return StandardException(loc, UnknownError, ostream.str());
00216                 }
00217     }
00218 }
00219 
00220 ecl::StandardException tryLockSemaphoreException(const char* loc) {
00221         int error_result = errno;
00222     switch ( error_result ) {
00223         case ( EINTR ) : {
00224             return StandardException(LOC,InterruptedError,"Waiting for the semaphore lock was interrupted by a system signal.");
00225         }
00226         case ( EINVAL ) : {
00227             return StandardException(LOC,InvalidArgError,"The semaphore was invalid or the timeout structure specified was invalid.");
00228         }
00229         case ( EAGAIN ) : {
00230             return StandardException(LOC,BlockingError,"The waiting operation could not be performed without blocking???");
00231         }
00232                 default         :
00233                 {
00234                         ostringstream ostream;
00235                         ostream << "Posix error " << error_result << ": " << strerror(error_result) << ".";
00236                         return StandardException(loc, UnknownError, ostream.str());
00237                 }
00238     }
00239 }
00240 
00241 } // namespace ipc
00242 
00243 #endif /* ECL_HAS_EXCEPTIONS */
00244 
00245 }; // namespace ecl
00246 
00247 #endif /* ECL_HAS_POSIX_SEMAPHORES */


ecl_ipc
Author(s): Daniel Stonier
autogenerated on Sun Oct 5 2014 23:35:45