00001 #ifndef PLATFORM_APERIOS
00002
00003 #include "SemaphoreManager.h"
00004 #include "Shared/debuget.h"
00005 #include <stdlib.h>
00006 #include <errno.h>
00007 #include <stdio.h>
00008 #include <exception>
00009 #include <stdexcept>
00010 #include <iostream>
00011
00012
00013
00014 #if defined(_SEM_SEMUN_UNDEFINED) || defined(__CYGWIN__)
00015 union semun
00016 {
00017 int val;
00018 struct semid_ds *buf;
00019 unsigned short int *array;
00020 struct seminfo *__buf;
00021 };
00022 #endif
00023
00024 using namespace std;
00025
00026 SemaphoreManager::SemaphoreManager()
00027 : sems(), nsem(sems_t::MAX_ENTRIES), semid(-1), mysem(sems.end()), refc(sems.end())
00028 {init();}
00029
00030 SemaphoreManager::SemaphoreManager(unsigned int numRequest)
00031 : sems(), nsem(numRequest+2), semid(-1), mysem(sems.end()), refc(sems.end())
00032 {init();}
00033
00034 void SemaphoreManager::init() {
00035 if(nsem>sems_t::MAX_ENTRIES) {
00036 cout << "SemaphoreManager created with request for " << nsem << " semaphores, but sems_t::MAX_ENTRIES is " << sems_t::MAX_ENTRIES << endl;
00037 nsem=sems_t::MAX_ENTRIES;
00038 }
00039 unsigned int req=nsem;
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 unsigned int lowbound=0;
00057 unsigned int highbound=nsem;
00058
00059 while(lowbound!=highbound) {
00060 semid=semget(IPC_PRIVATE,nsem,IPC_CREAT | IPC_EXCL | 0666);
00061 if(semid<0) {
00062 if(errno!=EINVAL && errno!=ENOSPC) {
00063 perror("ERROR: SemaphoreManager upper limit detection (semget)");
00064 exit(EXIT_FAILURE);
00065 }
00066
00067 highbound=nsem-1;
00068 } else {
00069
00070 if(semctl(semid,-1,IPC_RMID)<0) {
00071 perror("ERROR: SemaphoreManager destruction (semctl)");
00072 exit(EXIT_FAILURE);
00073 }
00074 lowbound=nsem;
00075 }
00076 nsem=(lowbound+highbound+1)/2;
00077 }
00078
00079 semid=semget(IPC_PRIVATE,nsem,IPC_CREAT | IPC_EXCL | 0666);
00080 if(semid<0) {
00081 perror("ERROR: SemaphoreManager construction (semget)");
00082 exit(EXIT_FAILURE);
00083 }
00084 if(nsem!=req)
00085 cerr << "WARNING: System can only allocate " << nsem << " semaphores per set for id=" << semid << " (SEMMSL or SEMMNS max reached). " << req << " were requested." << endl;
00086
00087
00088 unsigned short int semvals[sems_t::MAX_ENTRIES];
00089 for(unsigned int i=0; i<nsem; i++)
00090 semvals[i]=0;
00091 semun params;
00092 params.array=semvals;
00093 if(semctl(semid,-1,SETALL,params)<0) {
00094 perror("ERROR: SemaphoreManager construction (semctl)");
00095 exit(EXIT_FAILURE);
00096 }
00097
00098
00099 if(nsem!=sems_t::MAX_ENTRIES) {
00100
00101 while(sems.new_back()!=sems.end()) {}
00102
00103 for(unsigned int i=0; i<nsem; i++)
00104 sems.pop_front();
00105 }
00106
00107
00108 mysem=sems.new_front();
00109 if(mysem==sems.end()) {
00110 cerr << "ERROR: could not allocate SemaphoreManager internal lock" << endl;
00111 exit(EXIT_FAILURE);
00112 }
00113
00114 setValue(mysem,1);
00115
00116 refc=sems.new_front();
00117 if(refc==sems.end()) {
00118 cerr << "ERROR: could not allocate SemaphoreManager reference counter" << endl;
00119 exit(EXIT_FAILURE);
00120 }
00121
00122 setValue(refc,0);
00123
00124 }
00125
00126 SemaphoreManager::SemaphoreManager(const SemaphoreManager& mm)
00127 : sems(), nsem(mm.nsem), semid(mm.semid), mysem(mm.mysem), refc(mm.refc)
00128 {
00129 ASSERT(mm.semid!=-1,"Copy of SemaphoreManager with invalid semid!");
00130 lower(mysem,1);
00131 sems=mm.sems;
00132 raise(refc,1);
00133 raise(mysem,1);
00134
00135 }
00136
00137 SemaphoreManager& SemaphoreManager::operator=(const SemaphoreManager& mm) {
00138 if(&mm==this)
00139 return *this;
00140
00141
00142 if(semid==mm.semid) {
00143
00144 if(mm.semid!=-1)
00145 mm.lower(mm.mysem,1);
00146 mysem=mm.mysem;
00147 sems=mm.sems;
00148 nsem=mm.nsem;
00149 if(mm.semid!=-1)
00150 mm.raise(mm.mysem,1);
00151 } else {
00152
00153
00154 if(semid!=-1) {
00155 lower(mysem,1);
00156 if(!lower(refc,1,false)) {
00157
00158
00159 sems.erase(refc);
00160 sems.erase(mysem);
00161 for(semid_t it=sems.begin(); it!=sems.end(); it=sems.next(it))
00162 if(it<nsem)
00163 cerr << "Warning: semaphore id " << it << " from set " << semid << " was still active when the set was dereferenced" << endl;
00164 if(semctl(semid,-1,IPC_RMID)<0) {
00165 perror("ERROR: SemaphoreManager deletion from operator= (semctl)");
00166 exit(EXIT_FAILURE);
00167 }
00168 semid=-1;
00169 } else
00170 raise(mysem,1);
00171 }
00172 if(mm.semid!=-1)
00173 mm.lower(mm.mysem,1);
00174 mysem=mm.mysem;
00175 sems=mm.sems;
00176 nsem=mm.nsem;
00177 semid=mm.semid;
00178 if(mm.semid!=-1) {
00179 raise(refc=mm.refc,1);
00180 mm.raise(mm.mysem,1);
00181 }
00182
00183 }
00184 return *this;
00185 }
00186
00187 SemaphoreManager::~SemaphoreManager() {
00188 if(semid==-1)
00189 return;
00190
00191 lower(mysem,1);
00192 if(!lower(refc,1,false)) {
00193
00194
00195
00196
00197
00198
00199
00200
00201 if(semctl(semid,-1,IPC_RMID)<0) {
00202 perror("ERROR: SemaphoreManager deletion from destructor (semctl)");
00203 exit(EXIT_FAILURE);
00204 }
00205 semid=-1;
00206 } else
00207 raise(mysem,1);
00208 }
00209
00210 void SemaphoreManager::aboutToFork() {
00211 raise(refc,1);
00212 }
00213
00214 void SemaphoreManager::faultShutdown() {
00215 if(semctl(semid,-1,IPC_RMID)<0)
00216 perror("WARNING: SemaphoreManager faultShutdown (semctl)");
00217 semid=-1;
00218 }
00219
00220 SemaphoreManager::semid_t SemaphoreManager::getSemaphore() {
00221 lower(mysem,1);
00222 semid_t id=sems.new_front();
00223 raise(mysem,1);
00224 if(id!=sems.end())
00225 setValue(id,0);
00226 intrPolicy[id]=INTR_RETRY;
00227 return id;
00228 }
00229 void SemaphoreManager::releaseSemaphore(semid_t id) {
00230 lower(mysem,1);
00231 sems.erase(id);
00232 raise(mysem,1);
00233 }
00234
00235 bool SemaphoreManager::lower(semid_t id, unsigned int x, bool block) const {
00236 sembuf sb={id,-x,(block?0:IPC_NOWAIT)};
00237 while(semop(semid,&sb,1)<0) {
00238 if(errno==EAGAIN)
00239 return false;
00240 if(errno==EINTR) {
00241 switch(intrPolicy[id]) {
00242 case INTR_CANCEL_VERBOSE:
00243 perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00244 cerr << " semop was interrupted by signal, cancelling lower()";
00245 case INTR_CANCEL:
00246 return false;
00247 case INTR_RETRY_VERBOSE:
00248 perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00249 cerr << " semop was interrupted by signal. Trying again...";
00250 case INTR_RETRY:
00251 break;
00252 case INTR_THROW_VERBOSE:
00253 perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00254 cerr << " semop was interrupted by signal. Throwing exception...";
00255 case INTR_THROW:
00256 throw std::runtime_error("EINTR returned by lower semop");
00257 case INTR_EXIT:
00258 perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00259 cerr << " semop was interrupted by signal. Exiting...";
00260 exit(EXIT_FAILURE);
00261 }
00262 } else {
00263 perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00264 cerr << " ";
00265 if(errno==EIDRM) {
00266 cerr << "Semaphore set has been removed. " << endl;
00267 }
00268 if(errno==EINVAL) {
00269 cerr << "Semaphore set was deleted. " << endl;
00270 }
00271
00272 cerr << "Goodbye" << endl;
00273 exit(EXIT_FAILURE);
00274 }
00275 }
00276 return true;
00277 }
00278 void SemaphoreManager::raise(semid_t id, unsigned int x) const {
00279 sembuf sb={id,x,0};
00280 if(semop(semid,&sb,1)<0) {
00281 perror("ERROR: SemaphoreManager unable to raise semaphore (semop)");
00282 }
00283 }
00284 int SemaphoreManager::getValue(semid_t id) const {
00285 int ans=semctl(semid,id,GETVAL);
00286 if(ans<0)
00287 perror("ERROR: SemaphoreManager getValue (semctl)");
00288 return ans;
00289 }
00290 void SemaphoreManager::setValue(semid_t id, int x) const {
00291 semun params;
00292 params.val=x;
00293 if(semctl(semid,id,SETVAL,params)<0) {
00294 perror("ERROR: SemaphoreManager::setValue (semctl)");
00295 exit(EXIT_FAILURE);
00296 }
00297 }
00298 bool SemaphoreManager::testZero(semid_t id, bool block) const {
00299 sembuf sb={id,0,(block?0:IPC_NOWAIT)};
00300 while(semop(semid,&sb,1)<0) {
00301 int theErr=errno;
00302 if(theErr==EAGAIN)
00303 return false;
00304 if(theErr!=EINTR) {
00305 perror("ERROR: SemaphoreManager unable to testZero() (semop)");
00306 cerr << " ";
00307 if(theErr==EIDRM) {
00308 cerr << "Semaphore set has been removed. " << endl;
00309 } else if(theErr==EINVAL) {
00310 cerr << "Semaphore set was deleted. " << endl;
00311 } else {
00312 cerr << "Error code was " << theErr << endl;
00313 }
00314 cerr << "Goodbye" << endl;
00315 exit(EXIT_FAILURE);
00316 } else {
00317 switch(intrPolicy[id]) {
00318 case INTR_CANCEL_VERBOSE:
00319 perror("ERROR: SemaphoreManager unable to testZero (semop)");
00320 cerr << " semop was interrupted by signal, cancelling testZero()";
00321 case INTR_CANCEL:
00322 return false;
00323 case INTR_RETRY_VERBOSE:
00324 perror("ERROR: SemaphoreManager unable to testZero (semop)");
00325 cerr << " semop was interrupted by signal. Trying again...";
00326 case INTR_RETRY:
00327 break;
00328 case INTR_THROW_VERBOSE:
00329 perror("ERROR: SemaphoreManager unable to testZero (semop)");
00330 cerr << " semop was interrupted by signal. Throwing exception...";
00331 case INTR_THROW:
00332 throw std::runtime_error("EINTR returned by testZero semop");
00333 case INTR_EXIT:
00334 perror("ERROR: SemaphoreManager unable to testZero (semop)");
00335 cerr << " semop was interrupted by signal. Exiting...";
00336 exit(EXIT_FAILURE);
00337 }
00338 }
00339 }
00340 return true;
00341 }
00342 bool SemaphoreManager::testZero_add(semid_t id, unsigned int x, bool testblock, bool addblock) const {
00343
00344 sembuf sb[2]={
00345 {id,0,(testblock?0:IPC_NOWAIT)},
00346 {id,x,(addblock?0:IPC_NOWAIT)}
00347 };
00348 while(semop(semid,sb,2)<0) {
00349 int theErr=errno;
00350 if(theErr==EAGAIN)
00351 return false;
00352 if(theErr!=EINTR) {
00353 perror("ERROR: SemaphoreManager unable to testZero_add() (semop)");
00354 cerr << " ";
00355 if(theErr==EIDRM) {
00356 cerr << "Semaphore set has been removed. " << endl;
00357 } else if(theErr==EINVAL) {
00358 cerr << "Semaphore set was deleted. " << endl;
00359 } else {
00360 cerr << "Error code was " << theErr << endl;
00361 }
00362 cerr << "Goodbye" << endl;
00363 exit(EXIT_FAILURE);
00364 } else {
00365 switch(intrPolicy[id]) {
00366 case INTR_CANCEL_VERBOSE:
00367 perror("ERROR: SemaphoreManager unable to testZero_add (semop)");
00368 cerr << " semop was interrupted by signal, cancelling testZero_add()";
00369 case INTR_CANCEL:
00370 return false;
00371 case INTR_RETRY_VERBOSE:
00372 perror("ERROR: SemaphoreManager unable to testZero_add (semop)");
00373 cerr << " semop was interrupted by signal. Trying again...";
00374 case INTR_RETRY:
00375 break;
00376 case INTR_THROW_VERBOSE:
00377 perror("ERROR: SemaphoreManager unable to testZero_add (semop)");
00378 cerr << " semop was interrupted by signal. Throwing exception...";
00379 case INTR_THROW:
00380 throw std::runtime_error("EINTR returned by testZero_add semop");
00381 case INTR_EXIT:
00382 perror("ERROR: SemaphoreManager unable to testZero_add (semop)");
00383 cerr << " semop was interrupted by signal. Exiting...";
00384 exit(EXIT_FAILURE);
00385 }
00386 }
00387 }
00388 return true;
00389 }
00390 bool SemaphoreManager::add_testZero(semid_t id, unsigned int x, bool addblock, bool testblock) const {
00391 sembuf sb[2]={
00392 {id,x,(addblock?0:IPC_NOWAIT)},
00393 {id,0,(testblock?0:IPC_NOWAIT)}
00394 };
00395 while(semop(semid,sb,2)<0) {
00396 int theErr=errno;
00397 if(theErr==EAGAIN)
00398 return false;
00399 if(theErr!=EINTR) {
00400 perror("ERROR: SemaphoreManager unable to add_testZero() (semop)");
00401 cerr << " ";
00402 if(theErr==EIDRM) {
00403 cerr << "Semaphore set has been removed. " << endl;
00404 } else if(theErr==EINVAL) {
00405 cerr << "Semaphore set was deleted. " << endl;
00406 } else {
00407 cerr << "Error code was " << theErr << endl;
00408 }
00409 cerr << "Goodbye" << endl;
00410 exit(EXIT_FAILURE);
00411 } else {
00412 switch(intrPolicy[id]) {
00413 case INTR_CANCEL_VERBOSE:
00414 perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00415 cerr << " semop was interrupted by signal, cancelling add_testZero()";
00416 case INTR_CANCEL:
00417 return false;
00418 case INTR_RETRY_VERBOSE:
00419 perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00420 cerr << " semop was interrupted by signal. Trying again...";
00421 case INTR_RETRY:
00422 break;
00423 case INTR_THROW_VERBOSE:
00424 perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00425 cerr << " semop was interrupted by signal. Throwing exception...";
00426 case INTR_THROW:
00427 throw std::runtime_error("EINTR returned by add_testZero semop");
00428 case INTR_EXIT:
00429 perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00430 cerr << " semop was interrupted by signal. Exiting...";
00431 exit(EXIT_FAILURE);
00432 }
00433 }
00434 }
00435 return true;
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449 #endif //Aperios check