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