(file) Return to TraceMemoryHandler.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  1 thilo.boehm 1.1 //%2006////////////////////////////////////////////////////////////////////////
  2                 //
  3                 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
  4                 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
  5                 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
  6                 // IBM Corp.; EMC Corporation, The Open Group.
  7                 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
  8                 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
  9                 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10                 // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11                 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 12                 // EMC Corporation; Symantec Corporation; The Open Group.
 13                 //
 14                 // Permission is hereby granted, free of charge, to any person obtaining a copy
 15                 // of this software and associated documentation files (the "Software"), to
 16                 // deal in the Software without restriction, including without limitation the
 17                 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 18                 // sell copies of the Software, and to permit persons to whom the Software is
 19                 // furnished to do so, subject to the following conditions:
 20                 // 
 21                 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 22 thilo.boehm 1.1 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 23                 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 24                 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 25                 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 26                 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 27                 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 28                 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 29                 //
 30                 //==============================================================================
 31                 //
 32                 //%/////////////////////////////////////////////////////////////////////////////
 33                 
 34                 #ifdef PEGASUS_PLATFORM_ZOS_ZSERIES_IBM
 35                 #define _ISOC99_SOURCE
 36                 #include <stdio.h>
 37                 #include <stdarg.h>
 38                 #endif
 39                 
 40                 #include <Pegasus/Common/TraceMemoryHandler.h>
 41                 #include <iostream>
 42                 #include <fstream>
 43 thilo.boehm 1.1 
 44                 #define PEGASUS_TRC_BUFFER_WRAP_MARKER ""
 45                 #define PEGASUS_TRC_BUFFER_EOT_MARKER "*EOTRACE*"
 46                 #define PEGASUS_TRC_BUFFER_EOT_MARKER_LEN 9
 47                 
 48                 
 49                 //#define DBG(output) output
 50                 #define DBG(output)
 51                 
 52                 PEGASUS_USING_STD;
 53                 
 54                 PEGASUS_NAMESPACE_BEGIN
 55                 
 56                 ////////////////////////////////////////////////////////////////////////////////
 57                 //  Constructs TraceMemoryHandler with a default buffer size
 58                 ////////////////////////////////////////////////////////////////////////////////
 59                 TraceMemoryHandler::TraceMemoryHandler()
 60                 {
 61                     Uint32 traceAreaSize = PEGASUS_TRC_DEFAULT_BUFFER_SIZE_KB * 1024;
 62 kumpf       1.3 
 63                     _initialize(traceAreaSize);
 64 thilo.boehm 1.1 }
 65                 
 66                 ////////////////////////////////////////////////////////////////////////////////
 67                 //  Constructs TraceMemoryHandler with a custom buffer size
 68                 ////////////////////////////////////////////////////////////////////////////////
 69                 TraceMemoryHandler::TraceMemoryHandler( Uint32 bufferSize )
 70                 {
 71                     Uint32 traceAreaSize = bufferSize * 1024;
 72 kumpf       1.3 
 73                     _initialize(traceAreaSize);
 74 thilo.boehm 1.1 }
 75                 
 76                 ////////////////////////////////////////////////////////////////////////////////
 77                 //  Private method to (re-)initialize the memory buffer
 78                 ////////////////////////////////////////////////////////////////////////////////
 79                 void TraceMemoryHandler::_initialize( Uint32 traceAreaSize )
 80                 {
 81                     _dying = false;
 82                     _inUseCounter = 0;
 83                     _lockCounter  = 1;
 84                     _contentionCount = 0;
 85                     _numberOfLocksObtained = 0;
 86                     _traceFileName = 0;
 87                 
 88                 
 89                     _overflowBuffer = 0;
 90                     _overflowBufferSize = 0;
 91 kumpf       1.3 
 92 thilo.boehm 1.1     _traceArea = (struct traceArea_t*) new char[traceAreaSize];
 93 kumpf       1.3 
 94 thilo.boehm 1.1     // The final buffer size is the size of the allocated area, less the
 95                     // size of the header struct, less one byte reseved for a terminating 0
 96 kumpf       1.2     _traceArea->bufferSize = traceAreaSize - sizeof(struct traceArea_t) - 1;
 97 thilo.boehm 1.1     _traceArea->nextPos = 0;
 98 kumpf       1.2     _traceArea->traceBuffer = (char*) (&(_traceArea->traceBuffer) + 1);
 99 thilo.boehm 1.1     _leftBytesInBuffer = _traceArea->bufferSize-1;
100 kumpf       1.3 
101                     memcpy(_traceArea->eyeCatcher,
102 thilo.boehm 1.1            PEGASUS_TRC_BUFFER_EYE_CATCHER,
103                            PEGASUS_TRC_BUFFER_EYE_CATCHER_LEN);
104 kumpf       1.3 
105                     _appendMarker();
106 thilo.boehm 1.1 
107                     // The end of the trace buffer is always null terminated
108                     _traceArea->traceBuffer[_traceArea->bufferSize] = '\0';
109                 }
110                 
111                 ////////////////////////////////////////////////////////////////////////////////
112                 //  Destructs TraceMemoryHandler
113                 ////////////////////////////////////////////////////////////////////////////////
114                 TraceMemoryHandler::~TraceMemoryHandler()
115                 {
116                     // Signal to all callers and work in progress that this instance
117 kumpf       1.3     // will be destroyed soon.
118 thilo.boehm 1.1     // As from now, no other caller can get the the lock. They are blocked out.
119                     die();
120 kumpf       1.3 
121 thilo.boehm 1.1     // Debug code for the time being
122                     // dumpTraceBuffer("cimserver.memorydump.trc");
123 kumpf       1.3 
124 thilo.boehm 1.1     // Wait until all users have left the critical section
125                     while ( _inUseCounter.get() > 0 )
126                     {
127                         // In any case, lock the buffer unconditional
128 kumpf       1.3         _lockCounter.set(0);
129 thilo.boehm 1.1         // Wait for 10ms, to give other therads to finish work.
130                         Threads::sleep(10);
131                     }
132                 
133                     delete[] _overflowBuffer;
134                     delete[] _traceArea;
135 kumpf       1.3 
136 thilo.boehm 1.1     delete[] _traceFileName;
137                 }
138                 
139                 ////////////////////////////////////////////////////////////////////////////////
140                 //  Request to lock the memory buffer for writing a trace message.
141                 //
142                 //  The locking of the memory buffer is implemented using a spinlock over
143                 //  an atomic int. The lock is obtained when the atomic lock counter increment
144                 //  results in a lock count of 1. Otherwise the lock count is decremented
145                 //  and incremented again until we end up at 1.
146                 //  To be able to replace in instance of the TraceMemoryHandler, two flags
147                 //  are kept around to control the lock processing:
148 kumpf       1.3 //  _dying: This flag indicates that the traceMemoryHandler will soon be
149 thilo.boehm 1.1 //          destroyed and cannot be used any more. Active attempts to obtain
150                 //          a lock are given up, leaving the spin loop.
151                 //  _inUseCounter: Keeps track of how many callers are trying to obtain a lock
152                 //                 or currently hold the lock. This allows the destructor to
153                 //                 wait for all callers to complete before destroying the
154                 //                 instance.
155                 ////////////////////////////////////////////////////////////////////////////////
156                 inline Boolean TraceMemoryHandler::_lockBufferAccess()
157                 {
158                     if ( _dying )
159                     {
160 kumpf       1.3         // The memory tracing is about to end.
161 thilo.boehm 1.1         // The caller will never get the lock.
162                         return false;
163                     }
164                 
165                     // Keep track of work in progress
166                     _inUseCounter.inc();
167 kumpf       1.3 
168 thilo.boehm 1.1     // The lock is implemented as a spin loop, since the action to append
169                     // a trace message to the memory buffer is very short.
170                     while ( true )
171                     {
172                         if ( _dying )
173                         {
174 kumpf       1.3             // The memory tracing is about to end.
175 thilo.boehm 1.1             // The caller will never get the lock.
176                             _inUseCounter.dec();
177 kumpf       1.3             break;
178 thilo.boehm 1.1         }
179                 
180                         // If the lock counter not 1,an other caller is in the critical section.
181                         if ( _lockCounter.get() == 1 )
182                         {
183                             // Decrement the atomic lock counter and test if we do have lock:
184 kumpf       1.3             // _lockCounter == 0
185 thilo.boehm 1.1             if ( _lockCounter.decAndTestIfZero() )
186                             {
187 kumpf       1.3                 // We do have lock!
188 thilo.boehm 1.1                 _numberOfLocksObtained++;
189                                 return true;
190                             }
191                         }
192                         // I did not get the lock. So signal the scheduer to change the active
193 kumpf       1.3         // thread to allow other threads to proceed. This also prevents from
194                         // looping in a tight loop that causes a dead look due to the
195 thilo.boehm 1.1         // lock optaining thread does not get any time ot finsh his work.
196                         Threads::yield();
197                         _contentionCount.inc();
198 kumpf       1.3     }
199                 
200 thilo.boehm 1.1     return false;
201                 }
202                 
203                 ////////////////////////////////////////////////////////////////////////////////
204                 //  Unlock the memory buffer when no longer used for writing.
205                 ////////////////////////////////////////////////////////////////////////////////
206                 inline void TraceMemoryHandler::_unlockBufferAccess()
207                 {
208 kumpf       1.3     // set the lock counter to 1 to allow one next user to enter
209 thilo.boehm 1.1     // the critical section.
210                     _lockCounter.set(1);
211                     _inUseCounter.dec();
212                 }
213                 
214                 
215                 ////////////////////////////////////////////////////////////////////////////////
216                 // Tells an instance of the traceMemoryHandler that it will be destructed
217                 // soon and should accept no more requests for trace messages.
218                 ////////////////////////////////////////////////////////////////////////////////
219                 inline void TraceMemoryHandler::die()
220                 {
221                     _dying = true;
222                 }
223                 
224                 ////////////////////////////////////////////////////////////////////////////////
225                 // Appends a marker after the last trace message in the buffer
226 kumpf       1.3 // The pointer for loction of the next message is not moved,
227 thilo.boehm 1.1 // because the marker must be overwritten by the next message it self.
228                 ////////////////////////////////////////////////////////////////////////////////
229                 void TraceMemoryHandler::_appendMarker()
230                 {
231                     if (_leftBytesInBuffer > PEGASUS_TRC_BUFFER_EOT_MARKER_LEN )
232                     {
233                         // Marker does fit inot the buffer, so ...
234                         // ... append it the end of the last written message.
235                         memcpy(&(_traceArea->traceBuffer[_traceArea->nextPos]),
236                                PEGASUS_TRC_BUFFER_EOT_MARKER,
237                                PEGASUS_TRC_BUFFER_EOT_MARKER_LEN );
238                     }
239                     else
240                     {
241                         // Marker does not fit into the buffer, so ...
242                         // ... blank out the remainder of the buffer
243                         memset(&(_traceArea->traceBuffer[_traceArea->nextPos]),
244                                0,
245                                _leftBytesInBuffer);
246                 
247                         // ... and put marker to the front of the buffer
248 thilo.boehm 1.1         memcpy(&(_traceArea->traceBuffer[0]),
249                               PEGASUS_TRC_BUFFER_EOT_MARKER,
250                               PEGASUS_TRC_BUFFER_EOT_MARKER_LEN );
251                     }
252                 }
253                 
254                 ////////////////////////////////////////////////////////////////////////////////
255                 //  Dumps the buffer to a given file.
256                 //  This function is not fully implemented yet, but used in tests.
257                 //  It will be revisited at implementing PEGAGAUS_ASSERT
258                 ////////////////////////////////////////////////////////////////////////////////
259                 void TraceMemoryHandler::dumpTraceBuffer(const char* filename)
260                 {
261                     cerr << "Number of lock contentions is <"<< _contentionCount.get()
262                          << ">" << endl;
263                     cerr << "Number of obtained locks is <"<< _numberOfLocksObtained
264                          << ">" << endl;
265                 
266                     ofstream ofile(filename,ios::app&ios::out);
267                     if( ofile.good() )
268                     {
269 thilo.boehm 1.1         Boolean locked = _lockBufferAccess();
270                         ofile << _traceArea->traceBuffer << PEGASUS_STD(endl);
271                         if (locked )
272                         {
273                             _unlockBufferAccess();
274                         }
275                 
276 kumpf       1.3         ofile.close();
277 thilo.boehm 1.1    }
278                 }
279                 
280                 
281                 ////////////////////////////////////////////////////////////////////////////////
282                 //  Appends a simple fixed length message to the trace buffer
283                 //  WARNING: This is a private method that does not lock the trace buffer.
284                 //           Callers have to lock the buffer prior to calling this method.
285                 ////////////////////////////////////////////////////////////////////////////////
286                 inline void TraceMemoryHandler::_appendSimpleMessage(
287 kumpf       1.3     const char* message,
288 thilo.boehm 1.1     Uint32 msgLen )
289                 {
290                     if (_leftBytesInBuffer >= msgLen )
291                     {
292                         memcpy(&(_traceArea->traceBuffer[_traceArea->nextPos]),
293                                message,
294                                msgLen);
295 kumpf       1.3 
296 thilo.boehm 1.1         _traceArea->nextPos += msgLen;
297                         _leftBytesInBuffer -= msgLen;
298                     }
299                     else
300                     {
301                         // Message doesn't completely fit into buffer, so we need to wrap
302                         // it around.
303 kumpf       1.3 
304 thilo.boehm 1.1         // First fill the buffer till the end ...
305                         memcpy(&(_traceArea->traceBuffer[_traceArea->nextPos]),
306                                message,
307                                _leftBytesInBuffer);
308                 
309                         // ... and then add the rest at the beginning
310                         msgLen = msgLen - _leftBytesInBuffer;
311                         memcpy(&(_traceArea->traceBuffer[0]),
312                               message + _leftBytesInBuffer,
313                               msgLen );
314 kumpf       1.3 
315 thilo.boehm 1.1         _traceArea->nextPos = msgLen;
316                         _leftBytesInBuffer = _traceArea->bufferSize - msgLen;
317                     }
318                 
319                     return;
320                 }
321                 
322                 
323                 ////////////////////////////////////////////////////////////////////////////////
324                 //  Formats a trace message into the trace buffer
325                 ////////////////////////////////////////////////////////////////////////////////
326                 void TraceMemoryHandler::handleMessage(
327                     const char *message,
328                     Uint32 msgLen,
329                     const char *fmt, va_list argList)
330                 {
331                     if(!_lockBufferAccess())
332                     {
333                         // Give up, buffer is going to be destroyed
334                         return;
335                     }
336 kumpf       1.3 
337 thilo.boehm 1.1     // Handle the static part of the message
338                     _appendSimpleMessage(message, msgLen);
339 kumpf       1.3 
340 thilo.boehm 1.1     if (_leftBytesInBuffer == 0)
341                     {
342                         // Wrap the buffer
343                         _traceArea->nextPos = 0;
344                         _leftBytesInBuffer = _traceArea->bufferSize;
345                     }
346                 
347                 
348 kumpf       1.3     // In case the buffer is too short, we need to invoke vsnprintf twice and
349 thilo.boehm 1.1     // for this need a copy of the argList.
350                     va_list argListCopy;
351                     va_copy(argListCopy, argList);
352                 
353 kumpf       1.3 
354 thilo.boehm 1.1     // We just use vsnprintf to format the variable right into the buffer,
355                     // up to the amount of bytes left.
356                 #ifdef PEGASUS_OS_TYPE_WINDOWS
357                         // Windows until VC 8 does not support vsnprintf
358                         // need to use Windows equivalent function with the underscore
359 kumpf       1.3     int ttlMsgLen =
360                         _vsnprintf(&(_traceArea->traceBuffer[_traceArea->nextPos]),
361                                    _leftBytesInBuffer,
362                                    fmt,
363 thilo.boehm 1.1                    argList);
364                 #else
365 kumpf       1.3     int ttlMsgLen =
366                         vsnprintf(&(_traceArea->traceBuffer[_traceArea->nextPos]),
367                                   _leftBytesInBuffer,
368                                   fmt,
369 thilo.boehm 1.1                   argList);
370 kumpf       1.3 #endif
371                 
372 thilo.boehm 1.1     if (((Uint32)ttlMsgLen < _leftBytesInBuffer) &&
373                         (ttlMsgLen != -1))
374                     {
375                         ttlMsgLen++;  //Include the '/0'
376 kumpf       1.3 
377 thilo.boehm 1.1         _traceArea->nextPos += ttlMsgLen;
378                         _leftBytesInBuffer -= ttlMsgLen;
379                     }
380                     else
381                     {
382                         // Reached end of buffer and need to wrap.
383                         // This is a bit ugly, since we can't just resume after what had
384                         // already been written, but have to start all over.
385                         //
386                         // To do this we format the message to the overflow buffer, and copy
387                         // the rest of the message from there to the beginning of the trace
388 kumpf       1.3         // buffer.
389 thilo.boehm 1.1         // To save memory allocations, the overflow buffer is kept around
390                         // until it becomes to small and needs to be reallocated.
391                         if ((Uint32)ttlMsgLen > _overflowBufferSize)
392                         {
393                             if (_overflowBuffer != NULL )
394                             {
395                                 delete[] _overflowBuffer;
396                             }
397                             _overflowBufferSize = ttlMsgLen;
398                             _overflowBuffer = new char[_overflowBufferSize];
399                         }
400 kumpf       1.3 
401 thilo.boehm 1.1 #ifdef PEGASUS_OS_TYPE_WINDOWS
402                         // Windows until VC 8 does not support vsnprintf
403                         // need to use Windows equivalent function with the underscore
404                         ttlMsgLen = _vsnprintf(_overflowBuffer,
405                                                _overflowBufferSize,
406                                                fmt,
407                                                argListCopy);
408                 #else
409                         ttlMsgLen = vsnprintf(_overflowBuffer,
410                                               _overflowBufferSize,
411                                               fmt,
412                                               argListCopy);
413 kumpf       1.3 #endif
414                 
415 thilo.boehm 1.1 
416                         // Now calculate how much data we have to copy from the overflow
417                         // buffer back to the trace buffer.
418                         ttlMsgLen -= _leftBytesInBuffer;
419 kumpf       1.3 
420 thilo.boehm 1.1         // Copy the remainder of the trace message to the trace buffer
421                         memcpy(&(_traceArea->traceBuffer[0]),
422                                &(_overflowBuffer[_leftBytesInBuffer]),
423                                ttlMsgLen );
424                 
425                         _traceArea->nextPos = ttlMsgLen+1;
426                         _leftBytesInBuffer = _traceArea->bufferSize - _traceArea->nextPos;
427                     }
428                 
429                     // replace null terminator with line break
430                     _traceArea->traceBuffer[_traceArea->nextPos-1] = '\n';
431                 
432                     _appendMarker();
433 kumpf       1.3 
434 thilo.boehm 1.1     _unlockBufferAccess();
435                 }
436                 
437                 ////////////////////////////////////////////////////////////////////////////////
438                 //  Copies a simple trace message to trace buffer
439                 ////////////////////////////////////////////////////////////////////////////////
440                 void TraceMemoryHandler::handleMessage(const char *message, Uint32 msgLen)
441                 {
442                     if(!_lockBufferAccess())
443                     {
444                         // Give up, buffer is going to be destroyed
445                         return;
446                     }
447 kumpf       1.3 
448 thilo.boehm 1.1     // We include the terminating 0 in the message for easier handling
449                     msgLen++;
450                 
451                     _appendSimpleMessage(message, msgLen);
452                 
453                 
454                     // replace null terminator with line break
455                     _traceArea->traceBuffer[_traceArea->nextPos-1] = '\n';
456                 
457                     _appendMarker();
458                 
459                     _unlockBufferAccess();
460                 }
461                 
462                 ////////////////////////////////////////////////////////////////////////////////
463                 //  Checks if a given message file is usable
464                 ////////////////////////////////////////////////////////////////////////////////
465                 Boolean TraceMemoryHandler::isValidMessageDestination(const char* traceFileName)
466                 {
467                     TraceFileHandler traceFileHandler;
468                 
469 thilo.boehm 1.1     return traceFileHandler.isValidMessageDestination( traceFileName );
470                 }
471                 
472                 
473                 ////////////////////////////////////////////////////////////////////////////////
474                 //  Sets the message file in case we need to flush out the trace
475                 ////////////////////////////////////////////////////////////////////////////////
476                 Uint32 TraceMemoryHandler::setMessageDestination(const char* destination)
477                 {
478                     delete[] _traceFileName;
479 kumpf       1.3 
480 thilo.boehm 1.1     _traceFileName = new char[strlen(destination)+1];
481                     strcpy(_traceFileName, destination);
482                 
483                     return 0;
484                 }
485                 
486                 ////////////////////////////////////////////////////////////////////////////////
487                 //  Flushes the trace
488                 ////////////////////////////////////////////////////////////////////////////////
489                 void TraceMemoryHandler::flushTrace()
490                 {
491                     dumpTraceBuffer(_traceFileName);
492                 }
493                 
494                 PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2