SV_Semaphore_Complex.cpp

Go to the documentation of this file.
00001 // SV_Semaphore_Complex.cpp
00002 // SV_Semaphore_Complex.cpp,v 4.23 2006/03/14 21:15:49 sjiang Exp
00003 
00004 #include "ace/SV_Semaphore_Complex.h"
00005 #include "ace/Log_Msg.h"
00006 #include "ace/OS_NS_Thread.h"
00007 
00008 #if !defined (__ACE_INLINE__)
00009 #include "ace/SV_Semaphore_Complex.inl"
00010 #endif /* __ACE_INLINE__ */
00011 
00012 ACE_RCSID(ace, SV_Semaphore_Complex, "SV_Semaphore_Complex.cpp,v 4.23 2006/03/14 21:15:49 sjiang Exp")
00013 
00014 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00015 
00016 ACE_ALLOC_HOOK_DEFINE(ACE_SV_Semaphore_Complex)
00017 
00018 void
00019 ACE_SV_Semaphore_Complex::dump (void) const
00020 {
00021 #if defined (ACE_HAS_DUMP)
00022   ACE_TRACE ("ACE_SV_Semaphore_Complex::dump");
00023 #endif /* ACE_HAS_DUMP */
00024 }
00025 
00026 // initial value of process
00027 const int ACE_SV_Semaphore_Complex::BIGCOUNT_ = 10000;
00028 
00029 // Define the ACE_SV_Semaphore operation arrays for the semop() calls.
00030 sembuf ACE_SV_Semaphore_Complex::op_lock_[2] =
00031 {
00032   {0, 0, 0},                    // Wait for [0] (lock) to equal 0
00033   {0, 1, SEM_UNDO},             // then increment [0] to 1 - this locks it.
00034                                 // UNDO to release the lock if processes exit
00035                                 // before explicitly unlocking.
00036 };
00037 
00038 sembuf ACE_SV_Semaphore_Complex::op_endcreate_[2] =
00039 {
00040   {1, -1, SEM_UNDO},            // Decrement [1] (proc counter) with undo on
00041                                 // exit, UNDO to adjust proc counter if
00042                                 // process exits before explicitly calling close()
00043   {0, -1, SEM_UNDO},            // the decrement [0] (lock) back to 0
00044 };
00045 
00046 sembuf ACE_SV_Semaphore_Complex::op_open_[1] =
00047 {
00048   {1, -1, SEM_UNDO},            // Decrement [1] (proc counter) with undo on
00049                                 // exit.
00050 };
00051 
00052 sembuf ACE_SV_Semaphore_Complex::op_close_[3] =
00053 {
00054   {0, 0, 0},                    // Wait for [0] (lock) to equal 0
00055   {0, 1, SEM_UNDO},             // then increment [0] to 1 - this lock it
00056   {1, 1, SEM_UNDO},             // then increment [1] (proc counter)
00057 };
00058 
00059 sembuf ACE_SV_Semaphore_Complex::op_unlock_[1] =
00060 {
00061   {0, -1, SEM_UNDO},            // Decrement [0] (lock) back to 0
00062 };
00063 
00064 // Open or create an array of SV_Semaphores.  We return 0 if all is OK, else -1.
00065 
00066 int
00067 ACE_SV_Semaphore_Complex::open (key_t k,
00068                                 short create,
00069                                 int initial_value,
00070                                 u_short nsems,
00071                                 mode_t perms)
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 }
00160 
00161 int
00162 ACE_SV_Semaphore_Complex::open (const char *name,
00163                                 short flags,
00164                                 int initial_value,
00165                                 u_short nsems,
00166                                 mode_t perms)
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 }
00172 
00173 // Close a ACE_SV_Semaphore.  Unlike the remove above, this function
00174 // is for a process to call before it exits, when it is done with the
00175 // ACE_SV_Semaphore.  We "decrement" the counter of processes using
00176 // the ACE_SV_Semaphore, and if this was the last one, we can remove
00177 // the ACE_SV_Semaphore.
00178 
00179 int
00180 ACE_SV_Semaphore_Complex::close (void)
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 }
00215 
00216 ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex (key_t k,
00217                                                     short flags,
00218                                                     int initial_value,
00219                                                     u_short nsems,
00220                                                     mode_t perms)
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_LIB_TEXT ("%p\n"),  ACE_LIB_TEXT ("ACE_SV_Semaphore_Complex")));
00225 }
00226 
00227 ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex (const char *name,
00228                                                     short flags,
00229                                                     int initial_value,
00230                                                     u_short nsems,
00231                                                     mode_t perms)
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_LIB_TEXT ("%p\n"),  ACE_LIB_TEXT ("ACE_SV_Semaphore_Complex")));
00244 }
00245 
00246 ACE_SV_Semaphore_Complex::~ACE_SV_Semaphore_Complex (void)
00247 {
00248   ACE_TRACE ("ACE_SV_Semaphore_Complex::~ACE_SV_Semaphore_Complex");
00249   if (this->internal_id_ >= 0)
00250     this->close ();
00251 }
00252 
00253 ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex (void)
00254 {
00255   ACE_TRACE ("ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex");
00256   this->init ();
00257 }
00258 
00259 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 09:42:05 2006 for ACE by doxygen 1.3.6