/home/vlg/develop/libASSA/libassa/assa/Semaphore.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 //------------------------------------------------------------------------------
00003 // $Id: Semaphore.cpp,v 1.4 2006/07/20 02:30:54 vlg Exp $
00004 //------------------------------------------------------------------------------
00005 //                              Semaphore.C
00006 //------------------------------------------------------------------------------
00007 //  Copyright (c) 2000 by Vladislav Grinchenko
00008 //
00009 //  This library is free software; you can redistribute it and/or
00010 //  modify it under the terms of the GNU Library General Public
00011 //  License as published by the Free Software Foundation; either
00012 //  version 2 of the License, or (at your option) any later version.
00013 //------------------------------------------------------------------------------
00014 //  Created: 07/10/2000
00015 //------------------------------------------------------------------------------
00016 
00017 #if !defined(WIN32)
00018 
00019 #include <sstream>
00020 #include <string>
00021 #include <iomanip>
00022 
00023 #include "assa/Semaphore.h"
00024 
00025 using namespace ASSA;
00026 
00027 /*--- Static definitions and constants ---*/
00028 
00029 const int ASSA::Semaphore::BIGCOUNT = 10000;
00030 
00031 sembuf Semaphore::m_op_lock [2] =
00032 {
00033     {2, 0, 0},                  // Wait for [2] lock to equal 0,
00034     {2, 1, SEM_UNDO}            // then increment [2] to 1 - this locks it.
00035                                 // UNDO to release the lock if processes
00036                                 // exits before explicitly unlocking.
00037 };
00038 
00039 sembuf Semaphore::m_op_endcreate [2] =
00040 {
00041     {1, -1, SEM_UNDO},          // Decrement [1] (proc counter) with undo on 
00042                                 // exit,
00043     {2, -1, SEM_UNDO}           // then decrement [2] (lock) back to 0.
00044 };
00045 
00046 sembuf Semaphore::m_op_open [2] =
00047 {
00048     {1, -1, SEM_UNDO},          // Decrement [1] (proc counter) with undo on
00049                                 // exit.
00050 };
00051 
00052 sembuf Semaphore::m_op_close [3] =
00053 {
00054     {2, 0, 0},                  // Wait for [2] lock to equal 0,
00055     {2, 1, SEM_UNDO},           // then increment [2] to 1 - this locks it,
00056     {1, 1, SEM_UNDO}            // then increment [1] (proc counter)
00057 };
00058 
00059 sembuf Semaphore::m_op_unlock [1] =
00060 {
00061     {2, -1, SEM_UNDO}           // Decrement [2] (lock) back to 0
00062 };
00063 
00064 sembuf Semaphore::m_op_op [1] =
00065 {
00066     {0, 99, SEM_UNDO}           // Decrement or increment [0] with undo on
00067                                 // exit. The 99 is set to the actual amount
00068                                 // to add or substract (positive or negative)
00069 };
00070 
00071 
00072 //------------------------------------------------------------------------------
00073 
00074 
00075 int
00076 Semaphore::
00077 create (key_t key_, int initval_)
00078 {
00079     trace_with_mask("Semaphore::create", SEM);
00080 
00081     register int semval;
00082 
00083     union semnum {
00084         int              val;
00085         struct semid_ds* buf;
00086         ushort*          array;
00087     } semctrl_arg;
00088 
00089     if (IPC_PRIVATE == key_) {
00090         EL((ASSAERR,"Not intended for private semaphores\n"));
00091         return (-1);
00092     }
00093     else if (key_ == (key_t) -1) {
00094         EL((ASSAERR,"Probably an ftok() error by caller\n"));
00095         return (-1);
00096     }
00097     m_key = key_;
00098     bool done = false;
00099 
00100     while (!done) {
00101         if ( (m_id = semget (m_key, 3, 0666 | IPC_CREAT)) < 0) {
00102             EL((ASSAERR,"Permission problem or kernel tables full\n"));
00103             return (-1);
00104         }
00105         /*
00106           When the semaphore is created, we know that the value of
00107           all 3 set members is 0.
00108 
00109           Get a lock on the semaphore by waiting for [2] to equal 0,
00110           then increment it.
00111 
00112           There is a race condition here. There is a possibility 
00113           that between the semget(2) and semop(2) below, another
00114           process can cal Semaphore:::close () member function
00115           which can remove a semaphore if that process is the last
00116           one using it.
00117 
00118           Therefore, we handle the error condition of an invalid
00119           semaphore ID specially below, and if it does happen, we
00120           just go back and create it again.
00121         */
00122         
00123         if (semop (m_id, &m_op_lock[0], 2) < 0) {
00124             if (errno == EINVAL) {
00125                 continue;
00126             }
00127             EL((ASSAERR,"Can't lock semaphore\n"));
00128             Assure_exit (false);
00129         }
00130         done = true;
00131     } // while (!done)
00132 
00133     /*
00134       Get the value of the process counter. If it equals 0,
00135       then no one has initialized the semaphore yet.
00136     */
00137     if ((semval = semctl (m_id, 1, GETVAL, 0)) < 0) {
00138         EL((ASSAERR,"Can't GETVAL\n"));
00139         Assure_exit (false);
00140     }           
00141     
00142     if (semval == 0) {
00143         /*
00144           We could initalize by doing a SETALL, but that
00145           would clear the adjust value that we set when
00146           we locked the semaphore above. Instead, we'll do
00147           two system calls to initialize semaphore value [0]
00148           and process counter [1].
00149         */
00150         semctrl_arg.val = initval_;
00151         
00152         if (semctl (m_id, 0, SETVAL, semctrl_arg) < 0) {
00153             EL((ASSAERR,"Can't SETVAL[0]\n"));
00154             Assure_exit (false);
00155         }
00156         
00157         semctrl_arg.val = BIGCOUNT;
00158         
00159         if (semctl (m_id, 1, SETVAL, semctrl_arg) < 0) {
00160             EL((ASSAERR,"Can't SETVAL[1]\n"));
00161             Assure_exit (false);
00162         }
00163     } // if (semval == 0)
00164 
00165     /*--- Decrement the process counter and then release the lock. ---*/
00166 
00167     if (semop (m_id, &m_op_endcreate[0], 2) < 0) {
00168         EL((ASSAERR,"Error on semop (ndcreate)\n"));
00169         Assure_exit (false);
00170     }
00171     return (m_id);
00172 }
00173 
00174 int
00175 Semaphore::
00176 open (key_t key_)
00177 {
00178     trace_with_mask("Semaphore::open", SEM);
00179 
00180     if (IPC_PRIVATE == key_) {
00181         EL((ASSAERR,"Not intended for private semaphores\n"));
00182         return (-1);
00183     }
00184     else if (key_ == (key_t) -1) {
00185         EL((ASSAERR,"Probably an ftok() error by caller\n"));
00186         return (-1);
00187     }
00188 
00189     m_key = key_;
00190     
00191     if ((m_id = semget (m_key, 3, 0)) < 0) {
00192         EL((ASSAERR,"Error on semget(3)"));
00193         return (-1);
00194     }
00195     /*--- Decrement the process counter. No need for lock ---*/
00196     
00197     if (semop (m_id, &m_op_open[0], 1) < 0) {
00198         EL((ASSAERR,"Error on semget(open)\n"));
00199         Assure_exit(false);
00200     }       
00201     return (m_id);
00202 }
00203         
00204 void
00205 Semaphore::
00206 remove ()
00207 {
00208     trace_with_mask("Semaphore::remove", SEM);
00209 
00210     if (m_id < 0 || m_key == ((key_t) -1) ) return;
00211 
00212     if (semctl (m_id, 0, IPC_RMID, 0) < 0) {
00213         EL((ASSAERR,"Can't IPC_RMID\n"));
00214         Assure_exit(false);
00215     }
00216     init ();
00217 }
00218 
00219 void
00220 Semaphore::
00221 close ()
00222 {
00223     trace_with_mask("Semaphore::close", SEM);
00224 
00225     register int semval;
00226 
00227     if (m_id < 0) return;
00228 
00229     /*
00230       First get the lock on semaphore, then increment process  counter.
00231     */
00232     if (semop (m_id, &m_op_close[0], 3) < 0) {
00233         EL((ASSAERR,"Can't semop(2)\n"));
00234         Assure_exit(false);
00235     }
00236     /*
00237       Now that we have a lock, read the value of the process counter
00238       to see if this is the last reference to the semaphore.
00239       There is a race condition here (same as in Semaphore::create()).
00240     */
00241     if ((semval = semctl (m_id, 1, GETVAL, 0)) < 0) {
00242         EL((ASSAERR,"Can't GETVAL\n"));
00243         Assure_exit(false);
00244     }
00245     
00246     if (semval > BIGCOUNT) {
00247         EL((ASSAERR,"sem[1] > BIGCOUNT\n"));
00248         Assure_exit(false);
00249     }
00250     else if (semval == BIGCOUNT) {
00251         remove ();
00252     }
00253     else if (semop (m_id, &m_op_unlock[0], 1) < 0) {
00254         EL((ASSAERR,"Can't unlock\n"));
00255         Assure_exit(false);
00256     }
00257     /*--- Invalidate ---*/
00258     init ();
00259 }
00260 
00261 
00262 void 
00263 Semaphore::
00264 op (int value_)
00265 {
00266         /* Test if m_id is still valid. If it fails, then
00267      * next operation is failing because of it. If not,
00268      * then something else happens here.
00269      */
00270     trace_with_mask("Semaphore::op", SEM);
00271 
00272     int semval = 0;
00273     dump ();
00274 
00275     if ((semval = semctl (m_id, 1, GETVAL, 0)) < 0) {
00276         EL((ASSAERR,"Can't GETVAL\n"));
00277         Assure_exit (false);
00278     }
00279         /* This will fail on Solaris? */
00280 
00281     if ((m_op_op[0].sem_op = value_) == 0) {
00282         EL((ASSAERR,"Can't have value_ == 0\n"));
00283         Assure_exit(false);
00284     }
00285     
00286     if (semop (m_id, &m_op_op[0], 1) < 0) {
00287         EL((ASSAERR,"sem_op error\n"));
00288         Assure_exit(false);
00289     }
00290 }
00291 
00292 void 
00293 Semaphore::
00294 dump (void) const
00295 {
00296     trace_with_mask("Semaphore::dump", SEM);
00297     
00298     std::ostringstream msg;
00299     msg << "\n\n\tKey.....: ";
00300 
00301     if (m_key == (key_t) -1) {
00302         msg  << m_key;
00303     }
00304     else {
00305         msg << "0x" << std::hex << m_key << std::dec;
00306     }
00307 
00308     msg << "\n\tID......: " << m_id << "\n\n";
00309 
00310     if (m_id >= 0 && m_key >= (key_t) -1) {
00311         msg << "\tsemval [0]\tproc counter[1]\tlock [2]\n"
00312             << "\t----------\t---------------\t--------\n";
00313             
00314         /*--- Get value of element in semaphore set ---*/
00315         msg << "\t   "   << semctl (m_id, 0, GETVAL)
00316             << "\t\t   " << semctl (m_id, 1, GETVAL)
00317             << "\t\t   " << semctl (m_id, 2, GETVAL);
00318     }
00319     else { 
00320         msg << "Semaphore id = -1. No info is available."; 
00321     }
00322     msg << std::ends;
00323     DL((SEM,"%s\n\n", msg.str ().c_str ()));
00324 }
00325 
00326 #endif /* !defined(WIN32) */
00327 

Generated on Sun Aug 13 15:08:00 2006 for libassa by  doxygen 1.4.6