Drizzled Public API Documentation

CSMutex.cc
00001 /* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
00002  *
00003  * PrimeBase Media Stream for MySQL
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00018  *
00019  * Original author: Paul McCullagh (H&G2JCtL)
00020  * Continued development: Barry Leslie
00021  *
00022  * 2007-06-06
00023  *
00024  * A basic mutex (mutual exclusion) object.
00025  *
00026  */
00027 
00028 #include "CSConfig.h"
00029 
00030 #include <assert.h>
00031 #ifdef OS_WINDOWS
00032 extern int gettimeofday(struct timeval *tv, struct timezone *tz);
00033 #else
00034 #include <sys/time.h>
00035 #endif
00036 
00037 #include <unistd.h>
00038 
00039 #include "CSException.h"
00040 #include "CSMutex.h"
00041 #include "CSGlobal.h"
00042 #include "CSLog.h"
00043 
00044 /*
00045  * ---------------------------------------------------------------
00046  * A MUTEX ENTITY
00047  */
00048 
00049 CSMutex::CSMutex()
00050 #ifdef DEBUG
00051 :
00052 iLocker(NULL),
00053 trace(false)
00054 #endif
00055 {
00056   int err;
00057 
00058   if ((err = pthread_mutex_init(&iMutex, NULL)))
00059     CSException::throwOSError(CS_CONTEXT, err);
00060 }
00061 
00062 CSMutex::~CSMutex()
00063 {
00064   pthread_mutex_destroy(&iMutex);
00065 }
00066 
00067 void CSMutex::lock()
00068 {
00069   int err = 0;
00070 
00071 #ifdef DEBUG
00072   int waiting = 2000;
00073   while (((err = pthread_mutex_trylock(&iMutex)) == EBUSY) && (waiting > 0)) {
00074     usleep(500);
00075     waiting--;
00076   }
00077   if (err) {
00078     if (err == EBUSY) {
00079       CSL.logf(iLocker, CSLog::Protocol, "Thread holding lock.\n");
00080     }
00081     
00082     if ((err) || (err = pthread_mutex_lock(&iMutex)))
00083       CSException::throwOSError(CS_CONTEXT, err);
00084   }
00085 
00086   iLocker = CSThread::getSelf();
00087   if (trace)
00088     CSL.logf(iLocker, CSLog::Protocol, "Mutex locked\n");
00089 #else
00090   if ((err = pthread_mutex_lock(&iMutex)))
00091     CSException::throwOSError(CS_CONTEXT, err);
00092 #endif
00093 }
00094 
00095 void CSMutex::unlock()
00096 {
00097 #ifdef DEBUG
00098   if (trace)
00099     CSL.logf(iLocker, CSLog::Protocol, "Mutex unlocked\n");
00100   iLocker = NULL;
00101 #endif
00102   pthread_mutex_unlock(&iMutex);
00103 }
00104 
00105 /*
00106  * ---------------------------------------------------------------
00107  * A LOCK ENTITY
00108  */
00109 
00110 CSLock::CSLock():
00111 CSMutex(),
00112 iLockingThread(NULL),
00113 iLockCount(0)
00114 {
00115 }
00116 
00117 CSLock::~CSLock()
00118 {
00119 }
00120 
00121 void CSLock::lock()
00122 {
00123   int err;
00124 
00125   enter_();
00126   if (iLockingThread != self) {
00127     if ((err = pthread_mutex_lock(&iMutex)))
00128       CSException::throwOSError(CS_CONTEXT, err);
00129     iLockingThread = self;
00130   }
00131   iLockCount++;
00132   exit_();
00133 }
00134 
00135 void CSLock::unlock()
00136 {
00137   enter_();
00138   ASSERT(iLockingThread == self);
00139   if (!(--iLockCount)) {
00140     iLockingThread = NULL;
00141     pthread_mutex_unlock(&iMutex);
00142   }
00143   exit_();
00144 }
00145 
00146 bool CSLock::haveLock()
00147 {
00148   enter_();
00149   return_(iLockingThread == self);
00150 }
00151 
00152 /*
00153  * ---------------------------------------------------------------
00154  * A SYNCRONISATION ENTITY
00155  */
00156 
00157 CSSync::CSSync():
00158 CSLock()
00159 {
00160   int err;
00161 
00162   if ((err = pthread_cond_init(&iCondition, NULL)))
00163     CSException::throwOSError(CS_CONTEXT, err);
00164 }
00165 
00166 CSSync::~CSSync()
00167 {
00168   pthread_cond_destroy(&iCondition);
00169 }
00170 
00171 void CSSync::wait()
00172 {
00173   int err;
00174   int lock_count;
00175 
00176   enter_();
00177   ASSERT(iLockingThread == self);
00178   lock_count = iLockCount;
00179   iLockCount = 0;
00180   iLockingThread = NULL;
00181   err = pthread_cond_wait(&iCondition, &iMutex);
00182   iLockCount = lock_count;
00183   iLockingThread = self;
00184   if (err)
00185     CSException::throwOSError(CS_CONTEXT, err);
00186   exit_();
00187 }
00188 
00189 void CSSync::wait(time_t milli_sec)
00190 {
00191   struct timespec abstime;
00192   int       lock_count;
00193   int       err;
00194   uint64_t    micro_sec;
00195 
00196   enter_();
00197   struct timeval  now;
00198 
00199   /* Get the current time in microseconds: */
00200   gettimeofday(&now, NULL);
00201   micro_sec = (uint64_t) now.tv_sec * (uint64_t) 1000000 + (uint64_t) now.tv_usec;
00202   
00203   /* Add the timeout which is in milli seconds */
00204   micro_sec += (uint64_t) milli_sec * (uint64_t) 1000;
00205 
00206   /* Setup the end time, which is in nano-seconds. */
00207   abstime.tv_sec = (long) (micro_sec / 1000000);        /* seconds */
00208   abstime.tv_nsec = (long) ((micro_sec % 1000000) * 1000);  /* and nanoseconds */
00209 
00210   ASSERT(iLockingThread == self);
00211   lock_count = iLockCount;
00212   iLockCount = 0;
00213   iLockingThread = NULL;
00214   err = pthread_cond_timedwait(&iCondition, &iMutex, &abstime);
00215   iLockCount = lock_count;
00216   iLockingThread = self;
00217   if (err && err != ETIMEDOUT)
00218     CSException::throwOSError(CS_CONTEXT, err);
00219   exit_();
00220 }
00221 
00222 void CSSync::wakeup()
00223 {
00224   int err;
00225 
00226   if ((err = pthread_cond_broadcast(&iCondition)))
00227     CSException::throwOSError(CS_CONTEXT, err);
00228 }
00229 
00230 
00231