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
|