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
|