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 <iostream>
00010
00011
00012
00013 #if defined(_SEM_SEMUN_UNDEFINED) || defined(__CYGWIN__)
00014 union semun
00015 {
00016 int val;
00017 struct semid_ds *buf;
00018 unsigned short int *array;
00019 struct seminfo *__buf;
00020 };
00021 #endif
00022
00023 using namespace std;
00024
00025 SemaphoreManager::SemaphoreManager()
00026 : sems(), nsem(sems_t::MAX_ENTRIES), semid(-1), mysem(sems.end()), refc(sems.end())
00027 {
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 unsigned int lowbound=0;
00044 unsigned int highbound=nsem;
00045 while(lowbound!=highbound) {
00046 semid=semget(IPC_PRIVATE,nsem,IPC_CREAT | IPC_EXCL | 0666);
00047 if(semid<0) {
00048 if(errno!=EINVAL && errno!=ENOSPC) {
00049 perror("ERROR: SemaphoreManager upper limit detection (semget)");
00050 exit(EXIT_FAILURE);
00051 }
00052
00053 highbound=nsem-1;
00054 } else {
00055
00056 if(semctl(semid,-1,IPC_RMID)<0) {
00057 perror("ERROR: SemaphoreManager destruction (semctl)");
00058 exit(EXIT_FAILURE);
00059 }
00060 lowbound=nsem;
00061 }
00062 nsem=(lowbound+highbound+1)/2;
00063 }
00064 if(nsem!=sems_t::MAX_ENTRIES)
00065 cerr << "WARNING: System can only allocate " << nsem << " semaphores per set (SEMMSL). " << sems_t::MAX_ENTRIES << " were suggested." << endl;
00066
00067
00068 semid=semget(IPC_PRIVATE,nsem,IPC_CREAT | IPC_EXCL | 0666);
00069 if(semid<0) {
00070 perror("ERROR: SemaphoreManager construction (semget)");
00071 exit(EXIT_FAILURE);
00072 }
00073
00074
00075 unsigned short int semvals[sems_t::MAX_ENTRIES];
00076 for(unsigned int i=0; i<nsem; i++)
00077 semvals[i]=0;
00078 semun params;
00079 params.array=semvals;
00080 if(semctl(semid,-1,SETALL,params)<0) {
00081 perror("ERROR: SemaphoreManager construction (semctl)");
00082 exit(EXIT_FAILURE);
00083 }
00084
00085
00086 if(nsem!=sems_t::MAX_ENTRIES) {
00087
00088 while(sems.new_back()!=sems.end()) {}
00089
00090 for(unsigned int i=0; i<nsem; i++)
00091 sems.pop_front();
00092 }
00093
00094
00095 mysem=sems.new_front();
00096 if(mysem==sems.end()) {
00097 cerr << "ERROR: could not allocate SemaphoreManager internal lock" << endl;
00098 exit(EXIT_FAILURE);
00099 }
00100
00101 setValue(mysem,1);
00102
00103 refc=sems.new_front();
00104 if(refc==sems.end()) {
00105 cerr << "ERROR: could not allocate SemaphoreManager reference counter" << endl;
00106 exit(EXIT_FAILURE);
00107 }
00108
00109 setValue(refc,0);
00110
00111 }
00112
00113 SemaphoreManager::SemaphoreManager(const SemaphoreManager& mm)
00114 : sems(), nsem(mm.nsem), semid(mm.semid), mysem(mm.mysem), refc(mm.refc)
00115 {
00116 ASSERT(mm.semid!=-1,"Copy of SemaphoreManager with invalid semid!");
00117 lower(mysem,1);
00118 sems=mm.sems;
00119 raise(refc,1);
00120 raise(mysem,1);
00121
00122 }
00123
00124 SemaphoreManager& SemaphoreManager::operator=(const SemaphoreManager& mm) {
00125 if(&mm==this)
00126 return *this;
00127
00128
00129 if(semid==mm.semid) {
00130
00131 if(mm.semid!=-1)
00132 mm.lower(mm.mysem,1);
00133 mysem=mm.mysem;
00134 sems=mm.sems;
00135 nsem=mm.nsem;
00136 if(mm.semid!=-1)
00137 mm.raise(mm.mysem,1);
00138 } else {
00139
00140
00141 if(semid!=-1) {
00142 lower(mysem,1);
00143 if(!lower(refc,1,false)) {
00144
00145
00146 sems.erase(refc);
00147 sems.erase(mysem);
00148 for(semid_t it=sems.begin(); it!=sems.end(); it=sems.next(it))
00149 cerr << "Warning: semaphore id " << it << " from set " << semid << " was still active when the set was dereferenced" << endl;
00150 if(semctl(semid,-1,IPC_RMID)<0) {
00151 perror("ERROR: SemaphoreManager deletion from operator= (semctl)");
00152 exit(EXIT_FAILURE);
00153 }
00154 semid=-1;
00155 } else
00156 raise(mysem,1);
00157 }
00158 if(mm.semid!=-1)
00159 mm.lower(mm.mysem,1);
00160 mysem=mm.mysem;
00161 sems=mm.sems;
00162 nsem=mm.nsem;
00163 semid=mm.semid;
00164 if(mm.semid!=-1) {
00165 raise(refc=mm.refc,1);
00166 mm.raise(mm.mysem,1);
00167 }
00168
00169 }
00170 return *this;
00171 }
00172
00173 SemaphoreManager::~SemaphoreManager() {
00174 if(semid==-1)
00175 return;
00176
00177 lower(mysem,1);
00178 if(!lower(refc,1,false)) {
00179
00180
00181
00182
00183
00184
00185
00186
00187 if(semctl(semid,-1,IPC_RMID)<0) {
00188 perror("ERROR: SemaphoreManager deletion from destructor (semctl)");
00189 exit(EXIT_FAILURE);
00190 }
00191 semid=-1;
00192 } else
00193 raise(mysem,1);
00194 }
00195
00196 void SemaphoreManager::aboutToFork() {
00197 raise(refc,1);
00198 }
00199
00200 void SemaphoreManager::faultShutdown() {
00201 if(semctl(semid,-1,IPC_RMID)<0)
00202 perror("WARNING: SemaphoreManager faultShutdown (semctl)");
00203 semid=-1;
00204 }
00205
00206 SemaphoreManager::semid_t SemaphoreManager::getSemaphore() {
00207 lower(mysem,1);
00208 semid_t id=sems.new_front();
00209 raise(mysem,1);
00210 return id;
00211 }
00212 void SemaphoreManager::releaseSemaphore(semid_t id) {
00213 lower(mysem,1);
00214 sems.erase(id);
00215 raise(mysem,1);
00216 }
00217
00218 bool SemaphoreManager::lower(semid_t id, unsigned int x, bool block) const {
00219 sembuf sb={id,-x,(block?0:IPC_NOWAIT)};
00220 while(semop(semid,&sb,1)<0) {
00221 if(errno==EAGAIN)
00222 return false;
00223 perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00224 if(errno==EINTR) {
00225 cerr << " I was interrupted. Trying again...";
00226 } else {
00227 cerr << " ";
00228 if(errno==EIDRM) {
00229 cerr << "Semaphore set has been removed. " << endl;
00230 }
00231 if(errno==EINVAL) {
00232 cerr << "Semaphore set was deleted. " << endl;
00233 }
00234
00235 cerr << "Goodbye" << endl;
00236 exit(EXIT_FAILURE);
00237 }
00238 }
00239 return true;
00240 }
00241 void SemaphoreManager::raise(semid_t id, unsigned int x) const {
00242 sembuf sb={id,x,0};
00243 if(semop(semid,&sb,1)<0) {
00244 perror("ERROR: SemaphoreManager unable to raise semaphore (semop)");
00245 }
00246 }
00247 int SemaphoreManager::getValue(semid_t id) const {
00248 int ans=semctl(semid,id,GETVAL);
00249 if(ans<0)
00250 perror("ERROR: SemaphoreManager getValue (semctl)");
00251 return ans;
00252 }
00253 void SemaphoreManager::setValue(semid_t id, int x) const {
00254 semun params;
00255 params.val=x;
00256 if(semctl(semid,id,SETVAL,params)<0) {
00257 perror("ERROR: SemaphoreManager::setValue (semctl)");
00258 exit(EXIT_FAILURE);
00259 }
00260 }
00261 bool SemaphoreManager::testZero(semid_t id, bool block) const {
00262 sembuf sb={id,0,(block?0:IPC_NOWAIT)};
00263 while(semop(semid,&sb,1)<0) {
00264 int theErr=errno;
00265 if(theErr==EAGAIN)
00266 return false;
00267 if(theErr!=EINTR) {
00268 perror("ERROR: SemaphoreManager unable to testZero() (semop)");
00269 cerr << " ";
00270 if(theErr==EIDRM) {
00271 cerr << "Semaphore set has been removed. " << endl;
00272 } else if(theErr==EINVAL) {
00273 cerr << "Semaphore set was deleted. " << endl;
00274 } else {
00275 cerr << "Error code was " << theErr << endl;
00276 }
00277 cerr << "Goodbye" << endl;
00278 exit(EXIT_FAILURE);
00279 }
00280 }
00281 return true;
00282 }
00283 bool SemaphoreManager::testZero_add(semid_t id, unsigned int x, bool testblock, bool addblock) const {
00284
00285 sembuf sb[2]={
00286 {id,0,(testblock?0:IPC_NOWAIT)},
00287 {id,x,(addblock?0:IPC_NOWAIT)}
00288 };
00289 while(semop(semid,sb,2)<0) {
00290 int theErr=errno;
00291 if(theErr==EAGAIN)
00292 return false;
00293 if(theErr!=EINTR) {
00294 perror("ERROR: SemaphoreManager unable to testZero_add() (semop)");
00295 cerr << " ";
00296 if(theErr==EIDRM) {
00297 cerr << "Semaphore set has been removed. " << endl;
00298 } else if(theErr==EINVAL) {
00299 cerr << "Semaphore set was deleted. " << endl;
00300 } else {
00301 cerr << "Error code was " << theErr << endl;
00302 }
00303 cerr << "Goodbye" << endl;
00304 exit(EXIT_FAILURE);
00305 }
00306 }
00307 return true;
00308 }
00309 bool SemaphoreManager::add_testZero(semid_t id, unsigned int x, bool addblock, bool testblock) const {
00310 sembuf sb[2]={
00311 {id,x,(addblock?0:IPC_NOWAIT)},
00312 {id,0,(testblock?0:IPC_NOWAIT)}
00313 };
00314 while(semop(semid,sb,2)<0) {
00315 int theErr=errno;
00316 if(theErr==EAGAIN)
00317 return false;
00318 if(theErr!=EINTR) {
00319 perror("ERROR: SemaphoreManager unable to add_testZero() (semop)");
00320 cerr << " ";
00321 if(theErr==EIDRM) {
00322 cerr << "Semaphore set has been removed. " << endl;
00323 } else if(theErr==EINVAL) {
00324 cerr << "Semaphore set was deleted. " << endl;
00325 } else {
00326 cerr << "Error code was " << theErr << endl;
00327 }
00328 cerr << "Goodbye" << endl;
00329 exit(EXIT_FAILURE);
00330 }
00331 }
00332 return true;
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 #endif //Aperios check