Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

SemaphoreManager.cc

Go to the documentation of this file.
00001 #ifndef PLATFORM_APERIOS
00002 
00003 #include "SemaphoreManager.h"
00004 #include "Shared/debuget.h"
00005 #include "Thread.h"
00006 #include <cstdlib>
00007 #include <cerrno>
00008 #include <cstdio>
00009 #include <exception>
00010 #include <stdexcept>
00011 #include <iostream>
00012 #include <sys/types.h>
00013 #include <sys/sem.h>
00014 #include <cstring>
00015 #include <unistd.h>
00016 
00017 #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACH__)
00018 /* union semun is defined by including <sys/sem.h> */
00019 #else
00020 /*! @cond INTERNAL */
00021 /* according to X/OPEN we have to define it ourselves */
00022 union semun {
00023   int val;                  /* value for SETVAL */
00024   struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
00025   unsigned short *array;    /* array for GETALL, SETALL */
00026   /* Linux specific part: */
00027   struct seminfo *__buf;    /* buffer for IPC_INFO */
00028 };
00029 /*! @endcond */
00030 #endif
00031 
00032 using namespace std;
00033 
00034 SemaphoreManager::SemaphoreManager()
00035 : sems(), nsem(sems_t::MAX_ENTRIES), semid(-1), mysem(sems.end()), refc(sems.end())
00036 {init();}
00037 
00038 SemaphoreManager::SemaphoreManager(unsigned int numRequest)
00039 : sems(), nsem(numRequest+2), semid(-1), mysem(sems.end()), refc(sems.end())
00040 {init();}
00041 
00042 void SemaphoreManager::init() {
00043   if(nsem>sems_t::MAX_ENTRIES) {
00044     cout << "SemaphoreManager created with request for " << nsem << " semaphores, but sems_t::MAX_ENTRIES is " << sems_t::MAX_ENTRIES << endl;
00045     nsem=sems_t::MAX_ENTRIES;
00046   }
00047   unsigned int req=nsem;
00048 
00049   //the seminfo structure is kernel-private and I can't find a portable way to access
00050   //SEMMSL without it.
00051   /*semun params; 
00052   seminfo info;
00053   params.__buf=info;
00054   if(semctl(semid,-1,IPC_INFO,params)<0) {
00055     perror("WARNING: SemaphoreManager query (semctl)");
00056     //we'll just forge ahead with the default value...
00057     //exit(EXIT_FAILURE);
00058   } else {
00059     if(nsem>info.semmsl)
00060       nsem=info.semmsl;
00061   }*/
00062   
00063   //So instead we'll do a binary search for the size:
00064   unsigned int lowbound=0; //inclusive
00065   unsigned int highbound=nsem; //inclusive
00066   //note that first pass asks for highbound - if it succeeds there's no search
00067   while(lowbound!=highbound) {
00068     semid=semget(IPC_PRIVATE,nsem,IPC_CREAT | IPC_EXCL | 0666);
00069     if(semid<0) {
00070       if(errno!=EINVAL && errno!=ENOSPC) {
00071         perror("ERROR: SemaphoreManager upper limit detection (semget)");
00072         exit(EXIT_FAILURE);
00073       }
00074       //too big
00075       highbound=nsem-1;
00076     } else {
00077       //succeeded -- too low?
00078       if(semctl(semid,-1,IPC_RMID)<0) {
00079         perror("ERROR: SemaphoreManager destruction (semctl)");
00080         exit(EXIT_FAILURE);
00081       }
00082       lowbound=nsem;
00083     }
00084     nsem=(lowbound+highbound+1)/2;
00085   }
00086   //get the semaphore set
00087   semid=semget(IPC_PRIVATE,nsem,IPC_CREAT | IPC_EXCL | 0666);
00088   if(semid<0) {
00089     perror("ERROR: SemaphoreManager construction (semget)");
00090         exit(EXIT_FAILURE);
00091   }
00092   if(nsem!=req)
00093     cerr << "WARNING: System can only allocate " << nsem << " semaphores per set for id=" << semid << " (SEMMSL or SEMMNS max reached). " << req << " were requested." << endl;
00094     
00095   //initialize to 0 (unlocked)
00096   unsigned short int semvals[sems_t::MAX_ENTRIES];
00097   for(unsigned int i=0; i<nsem; i++)
00098     semvals[i]=0;
00099   semun params; 
00100   params.array=semvals;
00101   if(semctl(semid,-1,SETALL,params)<0) {
00102     perror("ERROR: SemaphoreManager construction (semctl)");
00103     exit(EXIT_FAILURE);
00104   }
00105   
00106   //burn any extra ids we couldn't actually get from the system
00107   if(nsem!=sems_t::MAX_ENTRIES) {
00108     //first use up all the IDs
00109     while(sems.new_back()!=sems.end()) {}
00110     //now free the first nsem
00111     for(unsigned int i=0; i<nsem; i++)
00112       sems.pop_front();
00113   }
00114     
00115   //take one for ourselves to lock handing out semaphores
00116   mysem=sems.new_front();
00117   if(mysem==sems.end()) {
00118     cerr << "ERROR: could not allocate SemaphoreManager internal lock" << endl;
00119     exit(EXIT_FAILURE);
00120   }
00121   //only one semaphore can be in the process of creation or release at any given time, we have the lock
00122   setValue(mysem,1);
00123   //take another for ourselves to use as a reference count on the semaphore set
00124   refc=sems.new_front();
00125   if(refc==sems.end()) {
00126     cerr << "ERROR: could not allocate SemaphoreManager reference counter" << endl;
00127     exit(EXIT_FAILURE);
00128   }
00129   //reference count starts at 0 -- underflow is signalled by negative count
00130   setValue(refc,0);
00131   //cerr << "Semaphore set " << semid << " created" << endl;
00132 }
00133 
00134 SemaphoreManager::SemaphoreManager(const SemaphoreManager& mm)
00135 : sems(), nsem(mm.nsem), semid(mm.semid), mysem(mm.mysem), refc(mm.refc)
00136 {
00137   ASSERT(mm.semid!=-1,"Copy of SemaphoreManager with invalid semid!");
00138   lower(mysem,1); //get a lock on the new set
00139   sems=mm.sems; //we didn't copy sems earlier because we need a lock for this
00140   raise(refc,1); //add 1 to reference counter for our new set
00141   raise(mysem,1); //release lock on new set
00142   //cerr << "Semaphore set " << semid << " copied" << endl;
00143 }
00144 
00145 SemaphoreManager& SemaphoreManager::operator=(const SemaphoreManager& mm) {
00146   if(&mm==this)
00147     return *this;
00148   //ASSERT(semid!=-1,"Assignment to SemaphoreManager with invalid semid!");
00149   //ASSERT(mm.semid!=-1,"Assignment of SemaphoreManager with invalid semid!");
00150   if(semid==mm.semid) {
00151     //both reference the same set, just update some fields
00152     if(mm.semid!=-1)
00153       mm.lower(mm.mysem,1); //get a lock on the new set
00154     mysem=mm.mysem;
00155     sems=mm.sems;
00156     nsem=mm.nsem;
00157     if(mm.semid!=-1)
00158       mm.raise(mm.mysem,1); //release lock on new set
00159   } else {
00160     //we're replacing one set with the other, need to dereference our current set
00161     //cerr << "Semaphore set " << semid << " dereferenced" << endl;
00162     if(semid!=-1) {
00163       lower(mysem,1); //lock current set
00164       if(!lower(refc,1,false)) { //remove 1 from the reference counter for our current set
00165         //ran out of references to the old set, delete it
00166         //cerr << "Semaphore set " << semid << " deleted" << endl;
00167         sems.erase(refc);
00168         sems.erase(mysem);
00169         for(semid_t it=sems.begin(); it!=sems.end(); it=sems.next(it))
00170           if(it<nsem)
00171             cerr << "Warning: semaphore id " << it << " from set " << semid << " was still active when the set was dereferenced" << endl;
00172         if(semctl(semid,-1,IPC_RMID)<0) {
00173           perror("ERROR: SemaphoreManager deletion from operator= (semctl)");
00174           exit(EXIT_FAILURE);
00175         }
00176         semid=-1;
00177       } else
00178         raise(mysem,1); // it's still referenced, unlock for others
00179     }
00180     if(mm.semid!=-1)
00181       mm.lower(mm.mysem,1); //get a lock on the new set
00182     mysem=mm.mysem;
00183     sems=mm.sems;
00184     nsem=mm.nsem;
00185     semid=mm.semid;
00186     if(mm.semid!=-1) {
00187       raise(refc=mm.refc,1); //add 1 to reference counter for our new set
00188       mm.raise(mm.mysem,1); //release lock on new set
00189     }
00190     //cerr << "Semaphore set " << semid << " assigned" << endl;
00191   }
00192   return *this;
00193 }
00194 
00195 SemaphoreManager::~SemaphoreManager() {
00196   if(semid==-1)
00197     return;
00198   //cerr << "Semaphore set " << semid << " dereferenced" << endl;
00199   lower(mysem,1); //lock current set
00200   if(!lower(refc,1,false)) { //remove 1 from the reference counter for our current set
00201     //ran out of references to the old set, delete it
00202     //cerr << "Semaphore set " << semid << " deleted" << endl;
00203     /* // on the final shutdown, the process-local copies can't tell if semaphores were freed remotely
00204     sems.erase(refc);
00205     sems.erase(mysem);
00206     for(semid_t it=sems.begin(); it!=sems.end(); it=sems.next(it))
00207       cerr << "Warning: semaphore id " << it << " from set " << semid << " was still active when the set was dereferenced" << endl;
00208     */
00209     if(semctl(semid,-1,IPC_RMID)<0) {
00210       perror("ERROR: SemaphoreManager deletion from destructor (semctl)");
00211       exit(EXIT_FAILURE);
00212     }
00213     semid=-1;
00214   } else
00215     raise(mysem,1);
00216 }
00217 
00218 void SemaphoreManager::aboutToFork() {
00219   raise(refc,1);
00220 }
00221 
00222 void SemaphoreManager::faultShutdown() {
00223   if(semid==-1)
00224     return; // already released set
00225   if(semctl(semid,-1,IPC_RMID)<0)
00226     perror("WARNING: SemaphoreManager faultShutdown (semctl)");
00227   semid=-1;
00228 }
00229 
00230 SemaphoreManager::semid_t SemaphoreManager::getSemaphore() {
00231   lower(mysem,1);
00232   semid_t id=sems.new_front();
00233   raise(mysem,1);
00234   if(id!=sems.end())
00235     setValue(id,0);
00236   intrPolicy[id]=INTR_RETRY;
00237   return id;
00238 }
00239 void SemaphoreManager::releaseSemaphore(semid_t id) {
00240   lower(mysem,1);
00241   sems.erase(id);
00242   raise(mysem,1);
00243 }
00244 
00245 bool SemaphoreManager::lower(semid_t id, unsigned int x, bool block/*=true*/) const {
00246   sembuf sb={id,(short)-x,short(block?0:IPC_NOWAIT)};
00247   while(true) {
00248     Thread::requestInterruptOnCancel();
00249     int res = semop(semid,&sb,1);
00250     int theErr = errno;
00251     Thread::unrequestInterruptOnCancel();
00252     if(res==0)
00253       break;
00254     if(theErr==EAGAIN)
00255       return false;
00256     if(theErr==EINTR) {
00257       switch(intrPolicy[id]) {
00258         case INTR_CANCEL_VERBOSE:
00259           perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00260           cerr << "       semop was interrupted by signal, cancelling lower()";
00261         case INTR_CANCEL:
00262           return false;
00263         case INTR_RETRY_VERBOSE:
00264           perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00265           cerr << "       semop was interrupted by signal.  Trying again...";
00266           break;
00267         case INTR_RETRY:
00268           break; //while loop will retry
00269         case INTR_THROW_VERBOSE:
00270           perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00271           cerr << "       semop was interrupted by signal.  Throwing exception...";
00272         case INTR_THROW:
00273           throw std::runtime_error("EINTR returned by lower semop");
00274         case INTR_EXIT:
00275           perror("ERROR: SemaphoreManager unable to lower semaphore (semop)");
00276           cerr << "       semop was interrupted by signal.  Exiting...";
00277           exit(EXIT_FAILURE);
00278       }
00279     } else {
00280       if(theErr==EIDRM)
00281         usleep(500000); // probably in the process of shutdown, wait half a second before complaining
00282       cerr << "ERROR: SemaphoreManager unable to lower semaphore (semop): " << strerror(theErr) << endl;
00283       cerr << "       ";
00284       if(theErr==EIDRM) {
00285         cerr << "Semaphore set has been removed.  " << endl;
00286       }
00287       if(theErr==EINVAL) {
00288         cerr << "Semaphore set was deleted.  " << endl;
00289       }
00290       //prevent recuring problems
00291       cerr << "Goodbye" << endl;
00292       exit(EXIT_FAILURE);
00293     }
00294   }
00295   return true;
00296 }
00297 void SemaphoreManager::raise(semid_t id, unsigned int x) const {
00298   sembuf sb={id,(short)x,0};
00299   if(semop(semid,&sb,1)<0) {
00300     perror("ERROR: SemaphoreManager unable to raise semaphore (semop)");
00301   }
00302 }
00303 int SemaphoreManager::getValue(semid_t id) const {
00304   int ans=semctl(semid,id,GETVAL);
00305   if(ans<0)
00306     perror("ERROR: SemaphoreManager getValue (semctl)");
00307   return ans;
00308 }
00309 void SemaphoreManager::setValue(semid_t id, int x) const {
00310   semun params; 
00311   params.val=x;
00312   if(semctl(semid,id,SETVAL,params)<0) {
00313     perror("ERROR: SemaphoreManager::setValue (semctl)");
00314     exit(EXIT_FAILURE);
00315   }
00316 }
00317 int SemaphoreManager::getNumZeroBlockers(semid_t id) const {
00318   int ans=semctl(semid,id,GETZCNT);
00319   if(ans<0)
00320     perror("ERROR: SemaphoreManager getNumZeroBlockers (semctl)");
00321   return ans;
00322 }
00323 bool SemaphoreManager::testZero(semid_t id, bool block/*=true*/) const {
00324   sembuf sb={id,0,short(block?0:IPC_NOWAIT)};
00325   while(true) {
00326     Thread::requestInterruptOnCancel();
00327     int res = semop(semid,&sb,1);
00328     int theErr = errno;
00329     Thread::unrequestInterruptOnCancel();
00330     if(res==0)
00331       break;
00332     if(theErr==EAGAIN)
00333       return false;
00334     if(theErr!=EINTR) { // && theErr!=ERESTART?
00335       if(theErr==EIDRM)
00336         usleep(500000); // probably in the process of shutdown, wait half a second before complaining
00337       cerr << "ERROR: SemaphoreManager unable to testZero() (semop): " << strerror(theErr) << '\n';
00338       cerr << "       ";
00339       if(theErr==EIDRM) {
00340         cerr << "Semaphore set has been removed.  " << endl;
00341       } else if(theErr==EINVAL) {
00342         cerr << "Semaphore set was deleted.  " << endl;
00343       } else {
00344         cerr << "Error code was " << theErr << endl;
00345       }
00346       cerr << "Goodbye" << endl;
00347       exit(EXIT_FAILURE);
00348     } else {
00349       switch(intrPolicy[id]) {
00350         case INTR_CANCEL_VERBOSE:
00351           perror("ERROR: SemaphoreManager unable to testZero (semop)");
00352           cerr << "       semop was interrupted by signal, cancelling testZero()";
00353         case INTR_CANCEL:
00354           return false;
00355         case INTR_RETRY_VERBOSE:
00356           perror("ERROR: SemaphoreManager unable to testZero (semop)");
00357           cerr << "       semop was interrupted by signal.  Trying again...";
00358           break;
00359         case INTR_RETRY:
00360           break; //while loop will retry
00361         case INTR_THROW_VERBOSE:
00362           perror("ERROR: SemaphoreManager unable to testZero (semop)");
00363           cerr << "       semop was interrupted by signal.  Throwing exception...";
00364         case INTR_THROW:
00365           throw std::runtime_error("EINTR returned by testZero semop");
00366         case INTR_EXIT:
00367           perror("ERROR: SemaphoreManager unable to testZero (semop)");
00368           cerr << "       semop was interrupted by signal.  Exiting...";
00369           exit(EXIT_FAILURE);
00370       }
00371     }
00372   }
00373   return true;
00374 }
00375 bool SemaphoreManager::testZero_add(semid_t id, int x, bool testblock/*=true*/, bool addblock/*=true*/) const {
00376   sembuf sb[2]={
00377     {id,0,short(testblock?0:IPC_NOWAIT)},
00378     {id,(short)x,short(addblock?0:IPC_NOWAIT)}
00379   };
00380   while(true) {
00381     Thread::requestInterruptOnCancel();
00382     int res = semop(semid,sb,2);
00383     int theErr = errno;
00384     try {
00385       Thread::unrequestInterruptOnCancel();
00386     } catch(...) { // thread cancelled
00387       if(res==0) { // if we weren't interrupted, then semop was successful, undo it
00388 #ifdef DEBUG
00389         ASSERT(lower(id,x,false),"Could not undo semop after thread cancel in testZero_add (would block?)");
00390 #else
00391         lower(id,x,true); // block should not occur
00392 #endif
00393       }
00394       throw;
00395     }
00396     if(res==0)
00397       break;
00398     if(theErr==EAGAIN)
00399       return false;
00400     if(theErr!=EINTR) { // && theErr!=ERESTART?
00401       if(theErr==EIDRM)
00402         usleep(500000); // probably in the process of shutdown, wait half a second before complaining
00403       cerr << "ERROR: SemaphoreManager unable to testZero_add() (semop): " << strerror(theErr) << '\n';
00404       cerr << "       ";
00405       if(theErr==EIDRM) {
00406         cerr << "Semaphore set has been removed.  " << endl;
00407       } else if(theErr==EINVAL) {
00408         cerr << "Semaphore set was deleted.  " << endl;
00409       } else {
00410         cerr << "Error code was " << theErr << endl;
00411       }
00412       cerr << "Goodbye" << endl;
00413       exit(EXIT_FAILURE);
00414     } else {
00415       switch(intrPolicy[id]) {
00416         case INTR_CANCEL_VERBOSE:
00417           perror("ERROR: SemaphoreManager unable to testZero_add (semop)");
00418           cerr << "       semop was interrupted by signal, cancelling testZero_add()";
00419         case INTR_CANCEL:
00420           return false;
00421         case INTR_RETRY_VERBOSE:
00422           perror("ERROR: SemaphoreManager unable to testZero_add (semop)");
00423           cerr << "       semop was interrupted by signal.  Trying again...";
00424           break;
00425         case INTR_RETRY:
00426           break; //while loop will retry
00427         case INTR_THROW_VERBOSE:
00428           perror("ERROR: SemaphoreManager unable to testZero_add (semop)");
00429           cerr << "       semop was interrupted by signal.  Throwing exception...";
00430         case INTR_THROW:
00431           throw std::runtime_error("EINTR returned by testZero_add semop");
00432         case INTR_EXIT:
00433           perror("ERROR: SemaphoreManager unable to testZero_add (semop)");
00434           cerr << "       semop was interrupted by signal.  Exiting...";
00435           exit(EXIT_FAILURE);
00436       }
00437     }
00438   }
00439   return true;
00440 }
00441 bool SemaphoreManager::add_testZero(semid_t id, int x, bool addblock/*=true*/, bool testblock/*=true*/) const {
00442   sembuf sb[2]={
00443     {id,(short)x,short(addblock?0:IPC_NOWAIT)},
00444     {id,0,short(testblock?0:IPC_NOWAIT)}
00445   };
00446   while(true) {
00447     Thread::requestInterruptOnCancel();
00448     int res = semop(semid,sb,2);
00449     int theErr = errno;
00450     Thread::unrequestInterruptOnCancel();
00451     if(res==0)
00452       break;
00453     if(theErr==EAGAIN)
00454       return false;
00455     if(theErr!=EINTR) { // && theErr!=ERESTART?
00456       if(theErr==EIDRM)
00457         usleep(500000); // probably in the process of shutdown, wait half a second before complaining
00458       cerr << "ERROR: SemaphoreManager unable to add_testZero() (semop): " << strerror(theErr) << '\n';
00459       cerr << "       ";
00460       if(theErr==EIDRM) {
00461         cerr << "Semaphore set has been removed.  " << endl;
00462       } else if(theErr==EINVAL) {
00463         cerr << "Semaphore set was deleted.  " << endl;
00464       } else {
00465         cerr << "Error code was " << theErr << endl;
00466       }
00467       cerr << "Goodbye" << endl;
00468       exit(EXIT_FAILURE);
00469     } else {
00470       switch(intrPolicy[id]) {
00471         case INTR_CANCEL_VERBOSE:
00472           perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00473           cerr << "       semop was interrupted by signal, cancelling add_testZero()";
00474         case INTR_CANCEL:
00475           return false;
00476         case INTR_RETRY_VERBOSE:
00477           perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00478           cerr << "       semop was interrupted by signal.  Trying again...";
00479           break;
00480         case INTR_RETRY:
00481           break; //while loop will retry
00482         case INTR_THROW_VERBOSE:
00483           perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00484           cerr << "       semop was interrupted by signal.  Throwing exception...";
00485         case INTR_THROW:
00486           throw std::runtime_error("EINTR returned by add_testZero semop");
00487         case INTR_EXIT:
00488           perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00489           cerr << "       semop was interrupted by signal.  Exiting...";
00490           exit(EXIT_FAILURE);
00491       }
00492     }
00493   }
00494   return true;
00495 }
00496 
00497 bool SemaphoreManager::add_testZero_add(semid_t id, int x1, int x2, bool add1block/*=true*/, bool testblock/*=true*/, bool add2block/*=true*/) const {
00498   sembuf sb[3]={
00499     {id,(short)x1,short(add1block?0:IPC_NOWAIT)},
00500     {id,0,short(testblock?0:IPC_NOWAIT)},
00501     {id,(short)x2,short(add2block?0:IPC_NOWAIT)}
00502   };
00503   while(true) {
00504     Thread::requestInterruptOnCancel();
00505     int res = semop(semid,sb,3);
00506     int theErr = errno;
00507     Thread::unrequestInterruptOnCancel();
00508     if(res==0)
00509       break;
00510     if(theErr==EAGAIN)
00511       return false;
00512     if(theErr!=EINTR) { // && theErr!=ERESTART?
00513       if(theErr==EIDRM)
00514         usleep(500000); // probably in the process of shutdown, wait half a second before complaining
00515       cerr << "ERROR: SemaphoreManager unable to add_testZero() (semop): " << strerror(theErr) << '\n';
00516       cerr << "       ";
00517       if(theErr==EIDRM) {
00518         cerr << "Semaphore set has been removed.  " << endl;
00519       } else if(theErr==EINVAL) {
00520         cerr << "Semaphore set was deleted.  " << endl;
00521       } else {
00522         cerr << "Error code was " << theErr << endl;
00523       }
00524       cerr << "Goodbye" << endl;
00525       exit(EXIT_FAILURE);
00526     } else {
00527       switch(intrPolicy[id]) {
00528         case INTR_CANCEL_VERBOSE:
00529           perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00530           cerr << "       semop was interrupted by signal, cancelling add_testZero()";
00531         case INTR_CANCEL:
00532           return false;
00533         case INTR_RETRY_VERBOSE:
00534           perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00535           cerr << "       semop was interrupted by signal.  Trying again...";
00536           break;
00537         case INTR_RETRY:
00538           break; //while loop will retry
00539         case INTR_THROW_VERBOSE:
00540           perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00541           cerr << "       semop was interrupted by signal.  Throwing exception...";
00542         case INTR_THROW:
00543           throw std::runtime_error("EINTR returned by add_testZero semop");
00544         case INTR_EXIT:
00545           perror("ERROR: SemaphoreManager unable to add_testZero (semop)");
00546           cerr << "       semop was interrupted by signal.  Exiting...";
00547           exit(EXIT_FAILURE);
00548       }
00549     }
00550   }
00551   return true;
00552 }
00553 
00554 /*! @file
00555  * @brief Implements SemaphoreManager, which initializes, manages, and releases a set of System V style semaphores
00556  * @author ejt (Creator)
00557  */
00558 
00559 #endif //Aperios check

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:50 2016 by Doxygen 1.6.3