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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2