ASSA::Semaphore Class Reference

#include <Semaphore.h>

List of all members.

Public Member Functions

 Semaphore ()
 Constructor.
virtual ~Semaphore ()
 Destructor.
int create (key_t key_, int initval_=1)
 Create a semaphore with a specified initial value.
int open (key_t key_)
 Open a semaphore that must already exist.
void close ()
 Close a semaphore.
void remove ()
 Remove a semaphore.
void wait ()
 Wait until a semaphore's value is greater then 0, then decrement it by 1 and return.
void signal ()
 Increment a semaphore by 1.
void op (int val_)
 General semaphore operation.
key_t key () const
 Get key.
int id () const
 Get id.
void dump (void) const
 Dump the objects state along with the state of the semaphore (if connected) to the log file.

Protected Member Functions

void init ()
 Initalize by invalidating data members.

Protected Attributes

key_t m_key
 Semaphore's key.
int m_id
 Semaphore's id.

Static Protected Attributes

static const int BIGCOUNT = 10000
static sembuf m_op_lock [2]
 Wait for lock to equal 0, then increment lock to 1 - this locks it.
static sembuf m_op_endcreate [2]
 Decrement process counter with undo on exit, then decrement lock back to 0.
static sembuf m_op_open [2]
 Decrement process counter with undo on exit.
static sembuf m_op_close [3]
 Wait for lock to equal 0, then increment lock to 1 (lock it), then increment process counter.
static sembuf m_op_unlock [1]
 Decremetn lock back to 0.
static sembuf m_op_op [1]
 Decrement or increment semaphore with undo on exit.


Detailed Description

Definition at line 64 of file Semaphore.h.


Constructor & Destructor Documentation

ASSA::Semaphore::Semaphore  )  [inline]
 

Constructor.

Definition at line 188 of file Semaphore.h.

References init(), ASSA::SEM, and trace_with_mask.

00189 {
00190     trace_with_mask("Semaphore::Semaphore", SEM);
00191 
00192     init ();
00193 }

ASSA::Semaphore::~Semaphore  )  [inline, virtual]
 

Destructor.

Definition at line 197 of file Semaphore.h.

References close(), m_id, ASSA::SEM, and trace_with_mask.

00198 {
00199     trace_with_mask("Semaphore::~Semaphore", SEM);
00200     
00201     if (m_id > 0) {
00202         this->close ();
00203     }
00204 }


Member Function Documentation

void Semaphore::close  ) 
 

Close a semaphore.

Unlike the Semaphore::remove () function, this function is for a process to call before it exits, when it is done with the semaphore. We decrement the counter of processes using the semaphore, and if this was the last one, Semaphore::remove () is called to remove the semaphore. Calling this method also invalidates object for subsequent operations.

Definition at line 219 of file Semaphore.cpp.

References Assure_exit, BIGCOUNT, EL, ASSA::ERROR, init(), m_id, m_op_close, m_op_unlock, remove(), ASSA::SEM, and trace_with_mask.

Referenced by ~Semaphore().

00220 {
00221     trace_with_mask("Semaphore::close", SEM);
00222 
00223     register int semval;
00224 
00225     if (m_id < 0) return;
00226 
00227     /*
00228       First get the lock on semaphore, then increment process  counter.
00229     */
00230     if (semop (m_id, &m_op_close[0], 3) < 0) {
00231         EL((ERROR,"Can't semop(2)\n"));
00232         Assure_exit(false);
00233     }
00234     /*
00235       Now that we have a lock, read the value of the process counter
00236       to see if this is the last reference to the semaphore.
00237       There is a race condition here (same as in Semaphore::create()).
00238     */
00239     if ((semval = semctl (m_id, 1, GETVAL, 0)) < 0) {
00240         EL((ERROR,"Can't GETVAL\n"));
00241         Assure_exit(false);
00242     }
00243     
00244     if (semval > BIGCOUNT) {
00245         EL((ERROR,"sem[1] > BIGCOUNT\n"));
00246         Assure_exit(false);
00247     }
00248     else if (semval == BIGCOUNT) {
00249         remove ();
00250     }
00251     else if (semop (m_id, &m_op_unlock[0], 1) < 0) {
00252         EL((ERROR,"Can't unlock\n"));
00253         Assure_exit(false);
00254     }
00255     /*--- Invalidate ---*/
00256     init ();
00257 }

int Semaphore::create key_t  key_,
int  initval_ = 1
 

Create a semaphore with a specified initial value.

If the semaphore already exists, we don't initialize it (of course).

Parameters:
key_ Semaphore's key
initval_ Initiali value (default : 1)
Returns:
The semaphore ID if all OK, else -1

Definition at line 75 of file Semaphore.cpp.

References Assure_exit, BIGCOUNT, EL, ASSA::ERROR, m_id, m_key, m_op_endcreate, m_op_lock, ASSA::SEM, and trace_with_mask.

00076 {
00077     trace_with_mask("Semaphore::create", SEM);
00078 
00079     register int semval;
00080 
00081     union semnum {
00082         int              val;
00083         struct semid_ds* buf;
00084         ushort*          array;
00085     } semctrl_arg;
00086 
00087     if (IPC_PRIVATE == key_) {
00088         EL((ERROR,"Not intended for private semaphores\n"));
00089         return (-1);
00090     }
00091     else if (key_ == (key_t) -1) {
00092         EL((ERROR,"Probably an ftok() error by caller\n"));
00093         return (-1);
00094     }
00095     m_key = key_;
00096     bool done = false;
00097 
00098     while (!done) {
00099         if ( (m_id = semget (m_key, 3, 0666 | IPC_CREAT)) < 0) {
00100             EL((ERROR,"Permission problem or kernel tables full\n"));
00101             return (-1);
00102         }
00103         /*
00104           When the semaphore is created, we know that the value of
00105           all 3 set members is 0.
00106 
00107           Get a lock on the semaphore by waiting for [2] to equal 0,
00108           then increment it.
00109 
00110           There is a race condition here. There is a possibility 
00111           that between the semget(2) and semop(2) below, another
00112           process can cal Semaphore:::close () member function
00113           which can remove a semaphore if that process is the last
00114           one using it.
00115 
00116           Therefore, we handle the error condition of an invalid
00117           semaphore ID specially below, and if it does happen, we
00118           just go back and create it again.
00119         */
00120         
00121         if (semop (m_id, &m_op_lock[0], 2) < 0) {
00122             if (errno == EINVAL) {
00123                 continue;
00124             }
00125             EL((ERROR,"Can't lock semaphore\n"));
00126             Assure_exit (false);
00127         }
00128         done = true;
00129     } // while (!done)
00130 
00131     /*
00132       Get the value of the process counter. If it equals 0,
00133       then no one has initialized the semaphore yet.
00134     */
00135     if ((semval = semctl (m_id, 1, GETVAL, 0)) < 0) {
00136         EL((ERROR,"Can't GETVAL\n"));
00137         Assure_exit (false);
00138     }           
00139     
00140     if (semval == 0) {
00141         /*
00142           We could initalize by doing a SETALL, but that
00143           would clear the adjust value that we set when
00144           we locked the semaphore above. Instead, we'll do
00145           two system calls to initialize semaphore value [0]
00146           and process counter [1].
00147         */
00148         semctrl_arg.val = initval_;
00149         
00150         if (semctl (m_id, 0, SETVAL, semctrl_arg) < 0) {
00151             EL((ERROR,"Can't SETVAL[0]\n"));
00152             Assure_exit (false);
00153         }
00154         
00155         semctrl_arg.val = BIGCOUNT;
00156         
00157         if (semctl (m_id, 1, SETVAL, semctrl_arg) < 0) {
00158             EL((ERROR,"Can't SETVAL[1]\n"));
00159             Assure_exit (false);
00160         }
00161     } // if (semval == 0)
00162 
00163     /*--- Decrement the process counter and then release the lock. ---*/
00164 
00165     if (semop (m_id, &m_op_endcreate[0], 2) < 0) {
00166         EL((ERROR,"Error on semop (ndcreate)\n"));
00167         Assure_exit (false);
00168     }
00169     return (m_id);
00170 }

void Semaphore::dump void   )  const
 

Dump the objects state along with the state of the semaphore (if connected) to the log file.

Definition at line 292 of file Semaphore.cpp.

References DL, ASSA::ends(), m_id, m_key, ASSA::SEM, and trace_with_mask.

Referenced by op().

00293 {
00294     trace_with_mask("Semaphore::dump", SEM);
00295     
00296     std::ostringstream msg;
00297     msg << "\n\n\tKey.....: ";
00298 
00299     if (m_key == (key_t) -1) {
00300         msg  << m_key;
00301     }
00302     else {
00303         msg << "0x" << std::hex << m_key << std::dec;
00304     }
00305 
00306     msg << "\n\tID......: " << m_id << "\n\n";
00307 
00308     if (m_id >= 0 && m_key >= (key_t) -1) {
00309         msg << "\tsemval [0]\tproc counter[1]\tlock [2]\n"
00310             << "\t----------\t---------------\t--------\n";
00311             
00312         /*--- Get value of element in semaphore set ---*/
00313         msg << "\t   "   << semctl (m_id, 0, GETVAL)
00314             << "\t\t   " << semctl (m_id, 1, GETVAL)
00315             << "\t\t   " << semctl (m_id, 2, GETVAL);
00316     }
00317     else { 
00318         msg << "Semaphore id = -1. No info is available."; 
00319     }
00320     msg << std::ends;
00321     DL((SEM,"%s\n\n", msg.str ().c_str ()));
00322 }

int ASSA::Semaphore::id  )  const [inline]
 

Get id.

Definition at line 134 of file Semaphore.h.

References m_id.

00134 { return m_id; }

void ASSA::Semaphore::init  )  [inline, protected]
 

Initalize by invalidating data members.

Definition at line 208 of file Semaphore.h.

References m_id, and m_key.

Referenced by close(), remove(), and Semaphore().

00209 {
00210     m_key = (key_t) -1;
00211     m_id  = -1;
00212 }   

key_t ASSA::Semaphore::key  )  const [inline]
 

Get key.

Definition at line 131 of file Semaphore.h.

References m_key.

00131 { return m_key; }

void Semaphore::op int  val_  ) 
 

General semaphore operation.

Increment or decrement by a user-specified amount (positive or negative; amount can't be zero!).

Definition at line 262 of file Semaphore.cpp.

References Assure_exit, dump(), EL, ASSA::ERROR, m_id, m_op_op, ASSA::SEM, and trace_with_mask.

Referenced by signal(), and wait().

00263 {
00264         /* Test if m_id is still valid. If it fails, then
00265      * next operation is failing because of it. If not,
00266      * then something else happens here.
00267      */
00268     trace_with_mask("Semaphore::op", SEM);
00269 
00270     int semval = 0;
00271     dump ();
00272 
00273     if ((semval = semctl (m_id, 1, GETVAL, 0)) < 0) {
00274         EL((ERROR,"Can't GETVAL\n"));
00275         Assure_exit (false);
00276     }
00277         /* This will fail on Solaris? */
00278 
00279     if ((m_op_op[0].sem_op = value_) == 0) {
00280         EL((ERROR,"Can't have value_ == 0\n"));
00281         Assure_exit(false);
00282     }
00283     
00284     if (semop (m_id, &m_op_op[0], 1) < 0) {
00285         EL((ERROR,"sem_op error\n"));
00286         Assure_exit(false);
00287     }
00288 }

int Semaphore::open key_t  key_  ) 
 

Open a semaphore that must already exist.

This function should be used, instead of Semaphore::create (), if the caller knows that the semaphore must already exist. For example, a client from a client-server pair would use this, if its server's responsibility to create the semaphore.

Parameters:
key_ Semaphore's key
Returns:
The semaphore id if OK, else -1.

Definition at line 174 of file Semaphore.cpp.

References Assure_exit, EL, ASSA::ERROR, m_id, m_key, m_op_open, ASSA::SEM, and trace_with_mask.

00175 {
00176     trace_with_mask("Semaphore::open", SEM);
00177 
00178     if (IPC_PRIVATE == key_) {
00179         EL((ERROR,"Not intended for private semaphores\n"));
00180         return (-1);
00181     }
00182     else if (key_ == (key_t) -1) {
00183         EL((ERROR,"Probably an ftok() error by caller\n"));
00184         return (-1);
00185     }
00186 
00187     m_key = key_;
00188     
00189     if ((m_id = semget (m_key, 3, 0)) < 0) {
00190         EL((ERROR,"Error on semget(3)"));
00191         return (-1);
00192     }
00193     /*--- Decrement the process counter. No need for lock ---*/
00194     
00195     if (semop (m_id, &m_op_open[0], 1) < 0) {
00196         EL((ERROR,"Error on semget(open)\n"));
00197         Assure_exit(false);
00198     }       
00199     return (m_id);
00200 }

void Semaphore::remove  ) 
 

Remove a semaphore.

This call is intended to be called by a server, for example, when it is being shut down, as we do an IPC_RMID on the semaphore, regardless whether other processes may be using it or not. Most other processes should use Semaphore::close () instead. Calling this method also invalidates object for subsequent operations.

Definition at line 204 of file Semaphore.cpp.

References Assure_exit, EL, ASSA::ERROR, init(), m_id, m_key, ASSA::SEM, and trace_with_mask.

Referenced by close().

00205 {
00206     trace_with_mask("Semaphore::remove", SEM);
00207 
00208     if (m_id < 0 || m_key == ((key_t) -1) ) return;
00209 
00210     if (semctl (m_id, 0, IPC_RMID, 0) < 0) {
00211         EL((ERROR,"Can't IPC_RMID\n"));
00212         Assure_exit(false);
00213     }
00214     init ();
00215 }

void ASSA::Semaphore::signal  )  [inline]
 

Increment a semaphore by 1.

Tanenbaum's UP operation.

Definition at line 224 of file Semaphore.h.

References op(), ASSA::SEM, and trace_with_mask.

00225 {
00226     trace_with_mask("Semaphore::signal", SEM);
00227     op (1);
00228 }

void ASSA::Semaphore::wait  )  [inline]
 

Wait until a semaphore's value is greater then 0, then decrement it by 1 and return.

Tanenbaum's DOWN operation.

Definition at line 216 of file Semaphore.h.

References op(), ASSA::SEM, and trace_with_mask.

00217 {
00218     trace_with_mask("Semaphore::wait", SEM);
00219     op (-1);
00220 }


Member Data Documentation

const int ASSA::Semaphore::BIGCOUNT = 10000 [static, protected]
 

Definition at line 154 of file Semaphore.h.

Referenced by close(), and create().

int ASSA::Semaphore::m_id [protected]
 

Semaphore's id.

Definition at line 151 of file Semaphore.h.

Referenced by close(), create(), dump(), id(), init(), op(), open(), remove(), and ~Semaphore().

key_t ASSA::Semaphore::m_key [protected]
 

Semaphore's key.

Definition at line 148 of file Semaphore.h.

Referenced by create(), dump(), init(), key(), open(), and remove().

sembuf Semaphore::m_op_close [static, protected]
 

Initial value:

{
    {2, 0, 0},                  
    {2, 1, SEM_UNDO},           
    {1, 1, SEM_UNDO}            
}
Wait for lock to equal 0, then increment lock to 1 (lock it), then increment process counter.

Definition at line 173 of file Semaphore.h.

Referenced by close().

sembuf Semaphore::m_op_endcreate [static, protected]
 

Initial value:

{
    {1, -1, SEM_UNDO},          
                                
    {2, -1, SEM_UNDO}           
}
Decrement process counter with undo on exit, then decrement lock back to 0.

Definition at line 163 of file Semaphore.h.

Referenced by create().

sembuf Semaphore::m_op_lock [static, protected]
 

Initial value:

{
    {2, 0, 0},                  
    {2, 1, SEM_UNDO}            
                                
                                
}
Wait for lock to equal 0, then increment lock to 1 - this locks it.

Definition at line 158 of file Semaphore.h.

Referenced by create().

sembuf Semaphore::m_op_op [static, protected]
 

Initial value:

{
    {0, 99, SEM_UNDO}           
                                
                                
}
Decrement or increment semaphore with undo on exit.

The 99 is set to the actual amount to add or substract (positive or negative).

Definition at line 183 of file Semaphore.h.

Referenced by op().

sembuf Semaphore::m_op_open [static, protected]
 

Initial value:

{
    {1, -1, SEM_UNDO},          
                                
}
Decrement process counter with undo on exit.

Definition at line 168 of file Semaphore.h.

Referenced by open().

sembuf Semaphore::m_op_unlock [static, protected]
 

Initial value:

{
    {2, -1, SEM_UNDO}           
}
Decremetn lock back to 0.

Definition at line 177 of file Semaphore.h.

Referenced by close().


The documentation for this class was generated from the following files:
Generated on Mon Dec 19 16:37:19 2005 for libassa by  doxygen 1.4.5