Back to index

salome-kernel  6.5.0
LocalTraceBufferPool.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 //  Author : Paul RASCLE (EDF)
00024 //  Module : KERNEL
00025 //  $Header: /home/server/cvs/KERNEL/KERNEL_SRC/src/SALOMELocalTrace/LocalTraceBufferPool.cxx,v 1.12.2.2.10.2.12.1 2012-04-12 14:05:31 vsr Exp $
00026 // Cf. C++ Users Journal, June 2004, Tracing Application Execution, Tomer Abramson
00027 //
00028 #include <iostream>
00029 #include <limits.h>
00030 #include <cassert>
00031 #include <string.h>
00032 #include <cstdio>
00033 
00034 #ifndef WIN32
00035 #include <dlfcn.h>
00036 #else
00037 #include <windows.h>
00038 #endif
00039 
00040 //#define _DEVDEBUG_
00041 #include "LocalTraceBufferPool.hxx"
00042 #include "BaseTraceCollector.hxx"
00043 #include "LocalTraceCollector.hxx"
00044 #include "FileTraceCollector.hxx"
00045 #include "utilities.h"
00046 
00047 // In case of truncated message, end of trace contains "...\n\0"
00048 
00049 #define TRUNCATED_MESSAGE "...\n"
00050 #define MAXMESS_LENGTH MAX_TRACE_LENGTH-5
00051 
00052 // Class static attributes initialisation
00053 
00054 LocalTraceBufferPool* LocalTraceBufferPool::_singleton = 0;
00055 //#ifndef WIN32
00056 //pthread_mutex_t LocalTraceBufferPool::_singletonMutex;
00057 //#else
00058 pthread_mutex_t LocalTraceBufferPool::_singletonMutex =
00059   PTHREAD_MUTEX_INITIALIZER;
00060 //#endif
00061 BaseTraceCollector *LocalTraceBufferPool::_myThreadTrace = 0;
00062 
00063 // ============================================================================
00077 // ============================================================================
00078 
00079 LocalTraceBufferPool* LocalTraceBufferPool::instance()
00080 {
00081   if (_singleton == 0) // no need of lock when singleton already exists
00082     {
00083       int ret;
00084       ret = pthread_mutex_lock(&_singletonMutex); // acquire lock to be alone
00085       if (_singleton == 0)                     // another thread may have got
00086         {                                      // the lock after the first test
00087           DEVTRACE("New buffer pool");
00088           LocalTraceBufferPool* myInstance = new LocalTraceBufferPool(); 
00089 
00090           new DESTRUCTOR_OF<LocalTraceBufferPool> (*myInstance);
00091           _singleton = myInstance;
00092 
00093           // --- start a trace Collector
00094 
00095           char* traceKind = getenv("SALOME_trace");
00096 
00097           if ( !traceKind || strcmp(traceKind,"local")==0 ) // mkr : 27.11.2006 : PAL13967 - Distributed supervision graphs - Problem with "SALOME_trace"
00098             {
00099               _myThreadTrace = LocalTraceCollector::instance();
00100             }
00101           else if (strncmp(traceKind,"file",strlen("file"))==0)
00102             {
00103               const char *fileName;
00104               if (strlen(traceKind) > strlen("file"))
00105                 fileName = &traceKind[strlen("file")+1];
00106               else
00107                 fileName = "/tmp/tracetest.log";
00108               
00109               _myThreadTrace = FileTraceCollector::instance(fileName);
00110             }
00111           else // --- try a dynamic library
00112             {
00113 #ifndef WIN32
00114               void* handle;
00115               std::string impl_name = std::string ("lib") + traceKind 
00116                 + std::string("TraceCollector.so");
00117               handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
00118 #else
00119               HINSTANCE handle;
00120               std::string impl_name = std::string ("lib") + traceKind + std::string(".dll");
00121               handle = LoadLibrary( impl_name.c_str() );
00122 #endif
00123               if ( handle )
00124                 {
00125                   typedef BaseTraceCollector * (*FACTORY_FUNCTION) (void);
00126 #ifndef WIN32
00127                   FACTORY_FUNCTION TraceCollectorFactory =
00128                     (FACTORY_FUNCTION) dlsym(handle, "SingletonInstance");
00129 #else
00130                   FACTORY_FUNCTION TraceCollectorFactory =
00131                     (FACTORY_FUNCTION)GetProcAddress(handle, "SingletonInstance");
00132 #endif
00133                   if ( !TraceCollectorFactory )
00134                   {
00135                                      std::cerr << "Can't resolve symbol: SingletonInstance" <<std::endl;
00136 #ifndef WIN32
00137                       std::cerr << "dlerror: " << dlerror() << std::endl;
00138 #endif
00139                       exit( 1 );
00140                     }
00141                   _myThreadTrace = (TraceCollectorFactory) ();
00142                 }
00143               else
00144                 {
00145                   std::cerr << "library: " << impl_name << " not found !" << std::endl;
00146                   assert(handle); // to give file and line
00147                   exit(1);        // in case assert is deactivated
00148                 }             
00149             }
00150           DEVTRACE("New buffer pool: end");
00151         }
00152       ret = pthread_mutex_unlock(&_singletonMutex); // release lock
00153     }
00154   return _singleton;
00155 }
00156 
00157 // ============================================================================
00165 // ============================================================================
00166 
00167 int LocalTraceBufferPool::insert(int traceType, const char* msg)
00168 {
00169 
00170   // get immediately a message number to control sequence (mutex protected)
00171 
00172   unsigned long myMessageNumber = lockedIncrement(_position);
00173 
00174   // wait until there is a free buffer in the pool
00175 
00176   int ret = -1;
00177   while (ret)
00178     {
00179       ret = sem_wait(&_freeBufferSemaphore);
00180       if (ret) perror(" LocalTraceBufferPool::insert, sem_wait");
00181     }
00182 
00183   // get the next free buffer available (mutex protected) 
00184 
00185   unsigned long myInsertPos = lockedIncrement(_insertPos);
00186 
00187   // fill the buffer with message, thread id and type (normal or abort)
00188 
00189   strncpy(_myBuffer[myInsertPos%TRACE_BUFFER_SIZE].trace,
00190           msg,
00191           MAXMESS_LENGTH); // last chars always "...\n\0" if msg too long
00192   _myBuffer[myInsertPos%TRACE_BUFFER_SIZE].threadId =pthread_self();//thread id
00193   _myBuffer[myInsertPos%TRACE_BUFFER_SIZE].traceType = traceType;
00194   _myBuffer[myInsertPos%TRACE_BUFFER_SIZE].position = myMessageNumber;
00195 
00196 
00197   // increment the full buffer semaphore
00198   // (if previously 0, awake thread in charge of trace)
00199 
00200   ret = sem_post(&_fullBufferSemaphore);
00201 
00202   // returns the number of free buffers
00203 
00204   sem_getvalue(&_freeBufferSemaphore, &ret);
00205   return ret;  
00206 }
00207 
00208 // ============================================================================
00214 // ============================================================================
00215 
00216 int LocalTraceBufferPool::retrieve(LocalTrace_TraceInfo& aTrace)
00217 {
00218 
00219   // wait until there is a buffer in the pool, with a message to print
00220 
00221   int ret = -1;
00222   while (ret)
00223     {
00224       ret = sem_wait(&_fullBufferSemaphore);
00225       if (ret) MESSAGE (" LocalTraceBufferPool::retrieve, sem_wait");
00226     }
00227 
00228   // get the next buffer to print
00229 
00230   unsigned long myRetrievePos = lockedIncrement(_retrievePos);
00231 
00232   // copy the buffer from the pool to the provided buffer
00233 
00234   memcpy((void*)&aTrace,
00235          (void*)&_myBuffer[myRetrievePos%TRACE_BUFFER_SIZE],
00236          sizeof(aTrace));
00237 
00238   // increment the free buffer semaphore
00239   // (if previously 0, awake one of the threads waiting to put a trace, if any)
00240   // there is no way to preserve the order of waiting threads if several
00241   // threads are waiting to put a trace: the waken up thread is not
00242   // necessarily the first thread to wait.
00243 
00244   ret = sem_post(&_freeBufferSemaphore);
00245 
00246   // returns the number of full buffers
00247 
00248   sem_getvalue(&_fullBufferSemaphore, &ret);
00249   return ret;
00250 }
00251 
00252 // ============================================================================
00260 // ============================================================================
00261 
00262 unsigned long LocalTraceBufferPool::toCollect()
00263 {
00264   return _insertPos - _retrievePos;
00265 }
00266 
00267 // ============================================================================
00271 // ============================================================================
00272 
00273 LocalTraceBufferPool::LocalTraceBufferPool()
00274 {
00275   //cerr << "LocalTraceBufferPool::LocalTraceBufferPool()" << endl;
00276 
00277   _insertPos   = ULONG_MAX;  // first increment will give 0
00278   _retrievePos = ULONG_MAX;
00279   _position=0;               // first message will have number = 1
00280 
00281   memset(_myBuffer, 0, sizeof(_myBuffer)); // to guarantee end of strings = 0
00282   for (int i=0; i<TRACE_BUFFER_SIZE; i++)
00283     strcpy(&(_myBuffer[i].trace[MAXMESS_LENGTH]),TRUNCATED_MESSAGE);
00284   int ret;
00285   ret=sem_init(&_freeBufferSemaphore, 0, TRACE_BUFFER_SIZE); // all buffer free
00286   if (ret!=0) IMMEDIATE_ABORT(ret);
00287   ret=sem_init(&_fullBufferSemaphore, 0, 0);                 // 0 buffer full
00288   if (ret!=0) IMMEDIATE_ABORT(ret);
00289   ret=pthread_mutex_init(&_incrementMutex,NULL); // default = fast mutex
00290   if (ret!=0) IMMEDIATE_ABORT(ret);
00291 
00292   //cerr << "LocalTraceBufferPool::LocalTraceBufferPool()-end" << endl;
00293 }
00294 
00295 // ============================================================================
00299 // ============================================================================
00300 
00301 LocalTraceBufferPool::~LocalTraceBufferPool()
00302 {
00303   int ret = pthread_mutex_lock(&_singletonMutex); // acquire lock to be alone
00304   if (_singleton)
00305     {
00306       DEVTRACE("LocalTraceBufferPool::~LocalTraceBufferPool()");
00307       delete (_myThreadTrace);
00308       _myThreadTrace = 0;
00309       int ret;
00310       ret=sem_destroy(&_freeBufferSemaphore);
00311       ret=sem_destroy(&_fullBufferSemaphore);
00312       ret=pthread_mutex_destroy(&_incrementMutex);
00313       DEVTRACE("LocalTraceBufferPool::~LocalTraceBufferPool()-end");
00314       _singleton = 0;
00315     }
00316   ret = pthread_mutex_unlock(&_singletonMutex); // release lock
00317 }
00318 
00319 // ============================================================================
00323 // ============================================================================
00324 
00325 unsigned long LocalTraceBufferPool::lockedIncrement(unsigned long& pos)
00326 {
00327   int ret;
00328   ret = pthread_mutex_lock(&_incrementMutex);   // lock access to counters
00329   unsigned long mypos = ++pos;
00330   ret = pthread_mutex_unlock(&_incrementMutex); // release lock
00331   return mypos;
00332 }
00333