$search
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 */