ACE_SV_Semaphore_Complex Class Reference

This is a more complex semaphore wrapper that handles race conditions for initialization correctly... More...

#include <SV_Semaphore_Complex.h>

Inheritance diagram for ACE_SV_Semaphore_Complex:

Inheritance graph
[legend]
Collaboration diagram for ACE_SV_Semaphore_Complex:

Collaboration graph
[legend]
List of all members.

Public Types

 ACE_CREATE = IPC_CREAT
 ACE_OPEN = 0
enum  { ACE_CREATE = IPC_CREAT, ACE_OPEN = 0 }

Public Member Functions

 ACE_SV_Semaphore_Complex (void)
 ACE_SV_Semaphore_Complex (key_t key, short create=ACE_SV_Semaphore_Complex::ACE_CREATE, int initial_value=1, u_short nsems=1, mode_t perms=ACE_DEFAULT_FILE_PERMS)
 ACE_SV_Semaphore_Complex (const char *name, short create=ACE_SV_Semaphore_Complex::ACE_CREATE, int initial_value=1, u_short nsems=1, mode_t perms=ACE_DEFAULT_FILE_PERMS)
 ~ACE_SV_Semaphore_Complex (void)
int open (const char *name, short flags=ACE_SV_Semaphore_Simple::ACE_CREATE, int initial_value=1, u_short nsems=1, mode_t perms=ACE_DEFAULT_FILE_PERMS)
int open (key_t key, short flags=ACE_SV_Semaphore_Simple::ACE_CREATE, int initial_value=1, u_short nsems=1, mode_t perms=ACE_DEFAULT_FILE_PERMS)
int close (void)
int acquire (u_short n=0, short flags=0) const
 Acquire the semaphore.
int acquire_read (u_short n=0, short flags=0) const
 Acquire a semaphore for reading.
int acquire_write (u_short n=0, short flags=0) const
 Acquire a semaphore for writing.
int tryacquire (u_short n=0, short flags=0) const
 Try to acquire the semaphore.
int tryacquire_read (u_short n=0, short flags=0) const
 Try to acquire the semaphore for reading.
int tryacquire_write (u_short n=0, short flags=0) const
 Try to acquire the semaphore for writing.
int release (u_short n=0, short flags=0) const
 Release the semaphore.
int op (short val, u_short n=0, short flags=0) const
int op (sembuf op_vec[], u_short n) const
 General ACE_SV_Semaphore operation on an array of SV_Semaphores.
int control (int cmd, semun arg, u_short n=0) const
int control (int cmd, int value=0, u_short n=0) const
void dump (void) const
 Dump the state of an object.

Public Attributes

 ACE_ALLOC_HOOK_DECLARE
 Declare the dynamic allocation hooks.

Static Private Attributes

static const int BIGCOUNT_ = 10000
static sembuf op_lock_ [2]
static sembuf op_endcreate_ [2]
static sembuf op_open_ [1]
static sembuf op_close_ [3]
static sembuf op_unlock_ [1]

Detailed Description

This is a more complex semaphore wrapper that handles race conditions for initialization correctly...

This code is a port to C++, inspired by: W. Richard Stevens from his book: UNIX Network Programming (Prentice Hall, ISBN 0-13-949876-1 - 1990). We provide a simpler and easier to understand interface to the System V Semaphore system calls. We create and use a 2 + n-member set for the requested <ACE_SV_Semaphore_Complex>. The first member, [0], is a counter used to know when all processes have finished with the <ACE_SV_Semaphore_Complex>. The counter is initialized to a large number, decremented on every create or open and incremented on every close. This way we can use the "adjust" feature provided by System V so that any process that exit's without calling <close> is accounted for. It doesn't help us if the last process does this (as we have no way of getting control to remove the <ACE_SV_Semaphore_Complex>) but it will work if any process other than the last does an exit (intentional or unintentional). The second member, [1], of the semaphore is used as a lock variable to avoid any race conditions in the <create> and <close> functions. The members beyond [1] are actual semaphore values in the array of semaphores, which may be sized by the user in the constructor.

Definition at line 54 of file SV_Semaphore_Complex.h.


Member Enumeration Documentation

anonymous enum

Enumerator:
ACE_CREATE 
ACE_OPEN 

Definition at line 57 of file SV_Semaphore_Complex.h.

00058   {
00059     ACE_CREATE = IPC_CREAT,
00060     ACE_OPEN   = 0
00061   };


Constructor & Destructor Documentation

ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex ( void   ) 

Definition at line 253 of file SV_Semaphore_Complex.cpp.

References ACE_TRACE, and ACE_SV_Semaphore_Simple::init().

00254 {
00255   ACE_TRACE ("ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex");
00256   this->init ();
00257 }

ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex ( key_t  key,
short  create = ACE_SV_Semaphore_Complex::ACE_CREATE,
int  initial_value = 1,
u_short  nsems = 1,
mode_t  perms = ACE_DEFAULT_FILE_PERMS 
)

Definition at line 216 of file SV_Semaphore_Complex.cpp.

References ACE_ERROR, ACE_TEXT, ACE_TRACE, and LM_ERROR.

00221 {
00222   ACE_TRACE ("ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex");
00223   if (this->open (k, flags, initial_value, nsems, perms) == -1)
00224     ACE_ERROR ((LM_ERROR,  ACE_TEXT ("%p\n"),  ACE_TEXT ("ACE_SV_Semaphore_Complex")));
00225 }

ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex ( const char *  name,
short  create = ACE_SV_Semaphore_Complex::ACE_CREATE,
int  initial_value = 1,
u_short  nsems = 1,
mode_t  perms = ACE_DEFAULT_FILE_PERMS 
)

Definition at line 227 of file SV_Semaphore_Complex.cpp.

References ACE_DEFAULT_SEM_KEY, ACE_ERROR, ACE_TEXT, ACE_TRACE, LM_ERROR, and ACE_SV_Semaphore_Simple::name_2_key().

00232 {
00233   ACE_TRACE ("ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex");
00234 
00235   key_t key;
00236 
00237   if (name == 0)
00238     key = ACE_DEFAULT_SEM_KEY;
00239   else
00240     key = this->name_2_key (name);
00241 
00242   if (this->open (key, flags, initial_value, nsems, perms) == -1)
00243     ACE_ERROR ((LM_ERROR,  ACE_TEXT ("%p\n"),  ACE_TEXT ("ACE_SV_Semaphore_Complex")));
00244 }

ACE_SV_Semaphore_Complex::~ACE_SV_Semaphore_Complex ( void   ) 

Definition at line 246 of file SV_Semaphore_Complex.cpp.

References ACE_TRACE, and close().

00247 {
00248   ACE_TRACE ("ACE_SV_Semaphore_Complex::~ACE_SV_Semaphore_Complex");
00249   if (this->internal_id_ >= 0)
00250     this->close ();
00251 }


Member Function Documentation

ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_INLINE int ACE_SV_Semaphore_Complex::acquire ( u_short  n = 0,
short  flags = 0 
) const

Acquire the semaphore.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 8 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and ACE_SV_Semaphore_Simple::acquire().

Referenced by ACE_Process_Semaphore::acquire(), acquire_read(), and acquire_write().

00009 {
00010   ACE_TRACE ("ACE_SV_Semaphore_Complex::acquire");
00011   return ACE_SV_Semaphore_Simple::acquire ((u_short) n + 2, flags);
00012 }

ACE_INLINE int ACE_SV_Semaphore_Complex::acquire_read ( u_short  n = 0,
short  flags = 0 
) const

Acquire a semaphore for reading.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 15 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and acquire().

00016 {
00017   ACE_TRACE ("ACE_SV_Semaphore_Complex::acquire_read");
00018   return this->acquire (n, flags);
00019 }

ACE_INLINE int ACE_SV_Semaphore_Complex::acquire_write ( u_short  n = 0,
short  flags = 0 
) const

Acquire a semaphore for writing.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 22 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and acquire().

00023 {
00024   ACE_TRACE ("ACE_SV_Semaphore_Complex::acquire_write");
00025   return this->acquire (n, flags);
00026 }

int ACE_SV_Semaphore_Complex::close ( void   ) 

Close an ACE_SV_Semaphore. Unlike the <remove> method, this method is for a process to call before it exits, when it is done with the ACE_SV_Semaphore. We "decrement" the counter of processes using the ACE_SV_Semaphore, and if this was the last one, we can remove the ACE_SV_Semaphore.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 180 of file SV_Semaphore_Complex.cpp.

References ACE_TRACE, BIGCOUNT_, ACE_SV_Semaphore_Simple::control(), GETVAL, ACE_SV_Semaphore_Simple::init(), op_close_, op_unlock_, ACE_SV_Semaphore_Simple::remove(), and ACE_OS::semop().

Referenced by ~ACE_SV_Semaphore_Complex().

00181 {
00182   ACE_TRACE ("ACE_SV_Semaphore_Complex::close");
00183   int semval;
00184 
00185   if (this->key_ == (key_t) - 1 || this->internal_id_ == -1)
00186     return -1;
00187 
00188   // The following semop() first gets a lock on the ACE_SV_Semaphore,
00189   // then increments [1] - the process number.
00190 
00191   if (ACE_OS::semop (this->internal_id_,
00192                      &ACE_SV_Semaphore_Complex::op_close_[0],
00193                      3) == -1)
00194     return -1;
00195 
00196   // Now that we have a lock, read the value of the process counter to
00197   // see if this is the last reference to the ACE_SV_Semaphore. There
00198   // is a race condition here - see the comments in create ().
00199 
00200   if ((semval = ACE_SV_Semaphore_Simple::control (GETVAL, 0, 1)) == -1)
00201     return -1;
00202 
00203   if (semval > ACE_SV_Semaphore_Complex::BIGCOUNT_)
00204     return -1;
00205   else if (semval == ACE_SV_Semaphore_Complex::BIGCOUNT_)
00206     return this->remove ();
00207   else
00208     {
00209       int result = ACE_OS::semop (this->internal_id_,
00210                                   &ACE_SV_Semaphore_Complex::op_unlock_[0], 1);
00211       this->init ();
00212       return result;
00213     }
00214 }

ACE_INLINE int ACE_SV_Semaphore_Complex::control ( int  cmd,
int  value = 0,
u_short  n = 0 
) const

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 78 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and ACE_SV_Semaphore_Simple::control().

00079 {
00080   ACE_TRACE ("ACE_SV_Semaphore_Complex::control");
00081   return ACE_SV_Semaphore_Simple::control (cmd, value, (u_short) n + 2);
00082 }

ACE_INLINE int ACE_SV_Semaphore_Complex::control ( int  cmd,
semun  arg,
u_short  n = 0 
) const

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 71 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and ACE_SV_Semaphore_Simple::control().

00072 {
00073   ACE_TRACE ("ACE_SV_Semaphore_Complex::control");
00074   return ACE_SV_Semaphore_Simple::control (cmd, arg, (u_short) n + 2);
00075 }

ACE_BEGIN_VERSIONED_NAMESPACE_DECL void ACE_SV_Semaphore_Complex::dump ( void   )  const

Dump the state of an object.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 19 of file SV_Semaphore_Complex.cpp.

References ACE_TRACE.

00020 {
00021 #if defined (ACE_HAS_DUMP)
00022   ACE_TRACE ("ACE_SV_Semaphore_Complex::dump");
00023 #endif /* ACE_HAS_DUMP */
00024 }

ACE_INLINE int ACE_SV_Semaphore_Complex::op ( sembuf  op_vec[],
u_short  n 
) const

General ACE_SV_Semaphore operation on an array of SV_Semaphores.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 64 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and ACE_SV_Semaphore_Simple::op().

00065 {
00066   ACE_TRACE ("ACE_SV_Semaphore_Complex::op");
00067   return ACE_SV_Semaphore_Simple::op (op_vec, (u_short) n + 2);
00068 }

ACE_INLINE int ACE_SV_Semaphore_Complex::op ( short  val,
u_short  n = 0,
short  flags = 0 
) const

General ACE_SV_Semaphore operation. Increment or decrement by a specific amount (positive or negative; amount can`t be zero).

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 57 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and ACE_SV_Semaphore_Simple::op().

00058 {
00059   ACE_TRACE ("ACE_SV_Semaphore_Complex::op");
00060   return ACE_SV_Semaphore_Simple::op (val, (u_short) n + 2, flags);
00061 }

int ACE_SV_Semaphore_Complex::open ( key_t  key,
short  flags = ACE_SV_Semaphore_Simple::ACE_CREATE,
int  initial_value = 1,
u_short  nsems = 1,
mode_t  perms = ACE_DEFAULT_FILE_PERMS 
)

Open or create an array of SV_Semaphores. We return 0 if all is OK, else -1.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 67 of file SV_Semaphore_Complex.cpp.

References ACE_CREATE, ACE_TRACE, BIGCOUNT_, ACE_SV_Semaphore_Simple::control(), EIDRM, GETVAL, ACE_SV_Semaphore_Simple::init(), ACE_SV_Semaphore_Simple::internal_id_, IPC_PRIVATE, ACE_SV_Semaphore_Simple::key_, op_endcreate_, op_lock_, op_open_, ACE_SV_Semaphore_Simple::sem_number_, ACE_OS::semget(), ACE_OS::semop(), and SETVAL.

00072 {
00073   ACE_TRACE ("ACE_SV_Semaphore_Complex::open");
00074   if (k == IPC_PRIVATE)
00075     return -1;
00076 
00077   this->key_ = k;
00078 
00079   // Must include a count for the 2 additional semaphores we use
00080   // internally.
00081   this->sem_number_ = nsems + 2;
00082 
00083   if (create == ACE_SV_Semaphore_Complex::ACE_CREATE)
00084     {
00085       int result;
00086 
00087       do
00088         {
00089           this->internal_id_ = ACE_OS::semget
00090             (this->key_,
00091              (u_short) 2 + nsems,
00092              perms | ACE_SV_Semaphore_Complex::ACE_CREATE);
00093 
00094           if (this->internal_id_ == -1)
00095             return -1; // permission problem or tables full
00096 
00097           // When the <ACE_SV_Semaphore_Complex> is created, we know
00098           // that the value of all 3 members is 0.  Get a lock on the
00099           // <ACE_SV_Semaphore_Complex> by waiting for [0] to equal 0,
00100           // then increment it.
00101 
00102           // There is a race condition here. There is the possibility
00103           // that between the <semget> above and the <semop> below,
00104           // another process can call out <close> function which can
00105           // remove the <ACE_SV_Semaphore> if that process is the last
00106           // one using it.  Therefor we handle the error condition of
00107           // an invalid <ACE_SV_Semaphore> ID specifically below, and
00108           // if it does happen, we just go back and create it again.
00109           result = ACE_OS::semop (this->internal_id_,
00110                                   &ACE_SV_Semaphore_Complex::op_lock_[0],
00111                                   2);
00112         }
00113       while (result == -1 && (errno == EINVAL || errno == EIDRM));
00114 
00115       if (result == -1)
00116         return -1;
00117 
00118       // Get the value of the process counter. If it equals 0, then no
00119       // one has initialized the ACE_SV_Semaphore yet.
00120 
00121       int semval = ACE_SV_Semaphore_Simple::control (GETVAL, 0, 1);
00122 
00123       if (semval == -1)
00124         return this->init ();
00125       else if (semval == 0)
00126         {
00127           // We should initialize by doing a SETALL, but that would
00128           // clear the adjust value that we set when we locked the
00129           // ACE_SV_Semaphore above. Instead we do system calls to
00130           // initialize [1], as well as all the nsems SV_Semaphores.
00131 
00132           if (ACE_SV_Semaphore_Simple::control (SETVAL,
00133                                                 ACE_SV_Semaphore_Complex::BIGCOUNT_,
00134                                                 1) == -1)
00135             return -1;
00136           else
00137             for (u_short i = 0; i < nsems; i++)
00138               if (this->control (SETVAL, initial_value, i) == -1)
00139                 return -1;
00140         }
00141 
00142       // Decrement the process counter and then release the lock.
00143       return ACE_OS::semop (this->internal_id_,
00144                             &ACE_SV_Semaphore_Complex::op_endcreate_[0],
00145                             2);
00146     }
00147   else
00148     {
00149       this->internal_id_ = ACE_OS::semget (this->key_, 2 + nsems, 0);
00150       if (this->internal_id_ == -1)
00151         return -1;                      // doesn't exist or tables full
00152 
00153       // Decrement the process counter. We don't need a lock to do this.
00154       if (ACE_OS::semop (this->internal_id_,
00155                          &ACE_SV_Semaphore_Complex::op_open_[0], 1) < 0)
00156         return this->init ();
00157       return 0;
00158     }
00159 }

int ACE_SV_Semaphore_Complex::open ( const char *  name,
short  flags = ACE_SV_Semaphore_Simple::ACE_CREATE,
int  initial_value = 1,
u_short  nsems = 1,
mode_t  perms = ACE_DEFAULT_FILE_PERMS 
)

Open or create an array of SV_Semaphores. We return 0 if all is OK, else -1.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 162 of file SV_Semaphore_Complex.cpp.

References ACE_TRACE, and ACE_SV_Semaphore_Simple::name_2_key().

00167 {
00168   ACE_TRACE ("ACE_SV_Semaphore_Complex::open");
00169   return this->open (ACE_SV_Semaphore_Simple::name_2_key (name),
00170                      flags, initial_value, nsems, perms);
00171 }

ACE_INLINE int ACE_SV_Semaphore_Complex::release ( u_short  n = 0,
short  flags = 0 
) const

Release the semaphore.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 50 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and ACE_SV_Semaphore_Simple::release().

Referenced by ACE_Process_Semaphore::release().

00051 {
00052   ACE_TRACE ("ACE_SV_Semaphore_Complex::release");
00053   return ACE_SV_Semaphore_Simple::release ((u_short) n + 2, flags);
00054 }

ACE_INLINE int ACE_SV_Semaphore_Complex::tryacquire ( u_short  n = 0,
short  flags = 0 
) const

Try to acquire the semaphore.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 29 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and ACE_SV_Semaphore_Simple::tryacquire().

Referenced by ACE_Process_Semaphore::tryacquire(), tryacquire_read(), and tryacquire_write().

00030 {
00031   ACE_TRACE ("ACE_SV_Semaphore_Complex::tryacquire");
00032   return ACE_SV_Semaphore_Simple::tryacquire ((u_short) n + 2, flags);
00033 }

ACE_INLINE int ACE_SV_Semaphore_Complex::tryacquire_read ( u_short  n = 0,
short  flags = 0 
) const

Try to acquire the semaphore for reading.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 36 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and tryacquire().

00037 {
00038   ACE_TRACE ("ACE_SV_Semaphore_Complex::tryacquire_read");
00039   return this->tryacquire (n, flags);
00040 }

ACE_INLINE int ACE_SV_Semaphore_Complex::tryacquire_write ( u_short  n = 0,
short  flags = 0 
) const

Try to acquire the semaphore for writing.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 43 of file SV_Semaphore_Complex.inl.

References ACE_TRACE, and tryacquire().

00044 {
00045   ACE_TRACE ("ACE_SV_Semaphore_Complex::tryacquire_write");
00046   return this->tryacquire (n, flags);
00047 }


Member Data Documentation

ACE_SV_Semaphore_Complex::ACE_ALLOC_HOOK_DECLARE

Declare the dynamic allocation hooks.

Reimplemented from ACE_SV_Semaphore_Simple.

Definition at line 141 of file SV_Semaphore_Complex.h.

const int ACE_SV_Semaphore_Complex::BIGCOUNT_ = 10000 [static, private]

Definition at line 144 of file SV_Semaphore_Complex.h.

Referenced by close(), and open().

sembuf ACE_SV_Semaphore_Complex::op_close_ [static, private]

Initial value:

{
  {0, 0, 0},                    
  {0, 1, SEM_UNDO},             
  {1, 1, SEM_UNDO},             
}

Definition at line 148 of file SV_Semaphore_Complex.h.

Referenced by close().

sembuf ACE_SV_Semaphore_Complex::op_endcreate_ [static, private]

Initial value:

{
  {1, -1, SEM_UNDO},            
                                
                                
  {0, -1, SEM_UNDO},            
}

Definition at line 146 of file SV_Semaphore_Complex.h.

Referenced by open().

sembuf ACE_SV_Semaphore_Complex::op_lock_ [static, private]

Initial value:

{
  {0, 0, 0},                    
  {0, 1, SEM_UNDO},             
                                
                                
}

Definition at line 145 of file SV_Semaphore_Complex.h.

Referenced by open().

sembuf ACE_SV_Semaphore_Complex::op_open_ [static, private]

Initial value:

{
  {1, -1, SEM_UNDO},            
                                
}

Definition at line 147 of file SV_Semaphore_Complex.h.

Referenced by open().

sembuf ACE_SV_Semaphore_Complex::op_unlock_ [static, private]

Initial value:

{
  {0, -1, SEM_UNDO},            
}

Definition at line 149 of file SV_Semaphore_Complex.h.

Referenced by close().


The documentation for this class was generated from the following files:
Generated on Tue Feb 2 17:35:43 2010 for ACE by  doxygen 1.4.7