Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /*
7 : ** prtrace.c -- NSPR Trace Instrumentation
8 : **
9 : ** Implement the API defined in prtrace.h
10 : **
11 : **
12 : **
13 : */
14 :
15 : #include <string.h>
16 : #include "primpl.h"
17 :
18 :
19 : #define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 )
20 : #define DEFAULT_BUFFER_SEGMENTS 2
21 :
22 : /*
23 : ** Enumerate states in a RName structure
24 : */
25 : typedef enum TraceState
26 : {
27 : Running = 1,
28 : Suspended = 2
29 : } TraceState;
30 :
31 : /*
32 : ** Define QName structure
33 : */
34 : typedef struct QName
35 : {
36 : PRCList link;
37 : PRCList rNameList;
38 : char name[PRTRACE_NAME_MAX+1];
39 : } QName;
40 :
41 : /*
42 : ** Define RName structure
43 : */
44 : typedef struct RName
45 : {
46 : PRCList link;
47 : PRLock *lock;
48 : QName *qName;
49 : TraceState state;
50 : char name[PRTRACE_NAME_MAX+1];
51 : char desc[PRTRACE_DESC_MAX+1];
52 : } RName;
53 :
54 :
55 : /*
56 : ** The Trace Facility database
57 : **
58 : */
59 : static PRLogModuleInfo *lm;
60 :
61 : static PRLock *traceLock; /* Facility Lock */
62 : static PRCList qNameList; /* anchor to all QName structures */
63 : static TraceState traceState = Running;
64 :
65 : /*
66 : ** in-memory trace buffer controls
67 : */
68 : static PRTraceEntry *tBuf; /* pointer to buffer */
69 : static PRInt32 bufSize; /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */
70 : static volatile PRInt32 next; /* index to next PRTraceEntry */
71 : static PRInt32 last; /* index of highest numbered trace entry */
72 :
73 : /*
74 : ** Real-time buffer capture controls
75 : */
76 : static PRInt32 fetchLastSeen = 0;
77 : static PRBool fetchLostData = PR_FALSE;
78 :
79 : /*
80 : ** Buffer write-to-file controls
81 : */
82 : static PRLock *logLock; /* Sync lock */
83 : static PRCondVar *logCVar; /* Sync Condidtion Variable */
84 : /*
85 : ** Inter-thread state communication.
86 : ** Controling thread writes to logOrder under protection of logCVar
87 : ** the logging thread reads logOrder and sets logState on Notify.
88 : **
89 : ** logSegments, logCount, logLostData must be read and written under
90 : ** protection of logLock, logCVar.
91 : **
92 : */
93 : static enum LogState
94 : {
95 : LogNotRunning, /* Initial state */
96 : LogReset, /* Causes logger to re-calc controls */
97 : LogActive, /* Logging in progress, set only by log thread */
98 : LogSuspend, /* Suspend Logging */
99 : LogResume, /* Resume Logging => LogActive */
100 : LogStop /* Stop the log thread */
101 : } logOrder, logState, localState; /* controlling state variables */
102 : static PRInt32 logSegments; /* Number of buffer segments */
103 : static PRInt32 logEntries; /* number of Trace Entries in the buffer */
104 : static PRInt32 logEntriesPerSegment; /* number of PRTraceEntries per buffer segment */
105 : static PRInt32 logSegSize; /* size of buffer segment */
106 : static PRInt32 logCount; /* number of segments pending output */
107 : static PRInt32 logLostData; /* number of lost log buffer segments */
108 :
109 : /*
110 : ** end Trace Database
111 : **
112 : */
113 :
114 : /*
115 : ** _PR_InitializeTrace() -- Initialize the trace facility
116 : */
117 0 : static void NewTraceBuffer( PRInt32 size )
118 : {
119 : /*
120 : ** calculate the size of the buffer
121 : ** round down so that each segment has the same number of
122 : ** trace entries
123 : */
124 0 : logSegments = DEFAULT_BUFFER_SEGMENTS;
125 0 : logEntries = size / sizeof(PRTraceEntry);
126 0 : logEntriesPerSegment = logEntries / logSegments;
127 0 : logEntries = logSegments * logEntriesPerSegment;
128 0 : bufSize = logEntries * sizeof(PRTraceEntry);
129 0 : logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry);
130 0 : PR_ASSERT( bufSize != 0);
131 0 : PR_LOG( lm, PR_LOG_ERROR,
132 : ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld",
133 : logSegments, logEntries, logEntriesPerSegment, logSegSize ));
134 :
135 :
136 0 : tBuf = PR_Malloc( bufSize );
137 0 : if ( tBuf == NULL )
138 : {
139 0 : PR_LOG( lm, PR_LOG_ERROR,
140 : ("PRTrace: Failed to get trace buffer"));
141 0 : PR_ASSERT( 0 );
142 : }
143 : else
144 : {
145 0 : PR_LOG( lm, PR_LOG_NOTICE,
146 : ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf));
147 : }
148 :
149 0 : next = 0;
150 0 : last = logEntries -1;
151 0 : logCount = 0;
152 0 : logLostData = PR_TRUE; /* not really on first call */
153 0 : logOrder = LogReset;
154 :
155 0 : } /* end NewTraceBuffer() */
156 :
157 : /*
158 : ** _PR_InitializeTrace() -- Initialize the trace facility
159 : */
160 0 : static void _PR_InitializeTrace( void )
161 : {
162 : /* The lock pointer better be null on this call */
163 0 : PR_ASSERT( traceLock == NULL );
164 :
165 0 : traceLock = PR_NewLock();
166 0 : PR_ASSERT( traceLock != NULL );
167 :
168 0 : PR_Lock( traceLock );
169 :
170 0 : PR_INIT_CLIST( &qNameList );
171 :
172 0 : lm = PR_NewLogModule("trace");
173 :
174 0 : bufSize = DEFAULT_TRACE_BUFSIZE;
175 0 : NewTraceBuffer( bufSize );
176 :
177 : /* Initialize logging controls */
178 0 : logLock = PR_NewLock();
179 0 : logCVar = PR_NewCondVar( logLock );
180 :
181 0 : PR_Unlock( traceLock );
182 0 : return;
183 : } /* end _PR_InitializeTrace() */
184 :
185 : /*
186 : ** Create a Trace Handle
187 : */
188 : PR_IMPLEMENT(PRTraceHandle)
189 : PR_CreateTrace(
190 : const char *qName, /* QName for this trace handle */
191 : const char *rName, /* RName for this trace handle */
192 : const char *description /* description for this trace handle */
193 : )
194 : {
195 : QName *qnp;
196 : RName *rnp;
197 0 : PRBool matchQname = PR_FALSE;
198 :
199 : /* Self initialize, if necessary */
200 0 : if ( traceLock == NULL )
201 0 : _PR_InitializeTrace();
202 :
203 : /* Validate input arguments */
204 0 : PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX );
205 0 : PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX );
206 0 : PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX );
207 :
208 0 : PR_LOG( lm, PR_LOG_DEBUG,
209 : ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName));
210 :
211 : /* Lock the Facility */
212 0 : PR_Lock( traceLock );
213 :
214 : /* Do we already have a matching QName? */
215 0 : if (!PR_CLIST_IS_EMPTY( &qNameList ))
216 : {
217 0 : qnp = (QName *) PR_LIST_HEAD( &qNameList );
218 : do {
219 0 : if ( strcmp(qnp->name, qName) == 0)
220 : {
221 0 : matchQname = PR_TRUE;
222 0 : break;
223 : }
224 0 : qnp = (QName *)PR_NEXT_LINK( &qnp->link );
225 0 : } while( qnp != (QName *)&qNameList );
226 : }
227 : /*
228 : ** If we did not find a matching QName,
229 : ** allocate one and initialize it.
230 : ** link it onto the qNameList.
231 : **
232 : */
233 0 : if ( matchQname != PR_TRUE )
234 : {
235 0 : qnp = PR_NEWZAP( QName );
236 0 : PR_ASSERT( qnp != NULL );
237 0 : PR_INIT_CLIST( &qnp->link );
238 0 : PR_INIT_CLIST( &qnp->rNameList );
239 0 : strcpy( qnp->name, qName );
240 0 : PR_APPEND_LINK( &qnp->link, &qNameList );
241 : }
242 :
243 : /* Do we already have a matching RName? */
244 0 : if (!PR_CLIST_IS_EMPTY( &qnp->rNameList ))
245 : {
246 0 : rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList );
247 : do {
248 : /*
249 : ** No duplicate RNames are allowed within a QName
250 : **
251 : */
252 0 : PR_ASSERT( strcmp(rnp->name, rName));
253 0 : rnp = (RName *)PR_NEXT_LINK( &rnp->link );
254 0 : } while( rnp != (RName *)&qnp->rNameList );
255 : }
256 :
257 : /* Get a new RName structure; initialize its members */
258 0 : rnp = PR_NEWZAP( RName );
259 0 : PR_ASSERT( rnp != NULL );
260 0 : PR_INIT_CLIST( &rnp->link );
261 0 : strcpy( rnp->name, rName );
262 0 : strcpy( rnp->desc, description );
263 0 : rnp->lock = PR_NewLock();
264 0 : rnp->state = Running;
265 0 : if ( rnp->lock == NULL )
266 : {
267 0 : PR_ASSERT(0);
268 : }
269 :
270 0 : PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */
271 0 : rnp->qName = qnp; /* point the RName to the QName */
272 :
273 : /* Unlock the Facility */
274 0 : PR_Unlock( traceLock );
275 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t",
276 : qName, qnp, rName, rnp ));
277 :
278 0 : return((PRTraceHandle)rnp);
279 : } /* end PR_CreateTrace() */
280 :
281 : /*
282 : **
283 : */
284 : PR_IMPLEMENT(void)
285 : PR_DestroyTrace(
286 : PRTraceHandle handle /* Handle to be destroyed */
287 : )
288 : {
289 0 : RName *rnp = (RName *)handle;
290 0 : QName *qnp = rnp->qName;
291 :
292 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s",
293 : qnp->name, rnp->name));
294 :
295 : /* Lock the Facility */
296 0 : PR_Lock( traceLock );
297 :
298 : /*
299 : ** Remove RName from the list of RNames in QName
300 : ** and free RName
301 : */
302 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p",
303 : rnp->name, rnp));
304 0 : PR_REMOVE_LINK( &rnp->link );
305 0 : PR_Free( rnp->lock );
306 0 : PR_DELETE( rnp );
307 :
308 : /*
309 : ** If this is the last RName within QName
310 : ** remove QName from the qNameList and free it
311 : */
312 0 : if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) )
313 : {
314 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p",
315 : qnp->name, qnp));
316 0 : PR_REMOVE_LINK( &qnp->link );
317 0 : PR_DELETE( qnp );
318 : }
319 :
320 : /* Unlock the Facility */
321 0 : PR_Unlock( traceLock );
322 0 : return;
323 : } /* end PR_DestroyTrace() */
324 :
325 : /*
326 : ** Create a TraceEntry in the trace buffer
327 : */
328 : PR_IMPLEMENT(void)
329 : PR_Trace(
330 : PRTraceHandle handle, /* use this trace handle */
331 : PRUint32 userData0, /* User supplied data word 0 */
332 : PRUint32 userData1, /* User supplied data word 1 */
333 : PRUint32 userData2, /* User supplied data word 2 */
334 : PRUint32 userData3, /* User supplied data word 3 */
335 : PRUint32 userData4, /* User supplied data word 4 */
336 : PRUint32 userData5, /* User supplied data word 5 */
337 : PRUint32 userData6, /* User supplied data word 6 */
338 : PRUint32 userData7 /* User supplied data word 7 */
339 : )
340 : {
341 : PRTraceEntry *tep;
342 : PRInt32 mark;
343 :
344 0 : if ( (traceState == Suspended )
345 0 : || ( ((RName *)handle)->state == Suspended ))
346 0 : return;
347 :
348 : /*
349 : ** Get the next trace entry slot w/ minimum delay
350 : */
351 0 : PR_Lock( traceLock );
352 :
353 0 : tep = &tBuf[next++];
354 0 : if ( next > last )
355 0 : next = 0;
356 0 : if ( fetchLostData == PR_FALSE && next == fetchLastSeen )
357 0 : fetchLostData = PR_TRUE;
358 :
359 0 : mark = next;
360 :
361 0 : PR_Unlock( traceLock );
362 :
363 : /*
364 : ** We have a trace entry. Fill it in.
365 : */
366 0 : tep->thread = PR_GetCurrentThread();
367 0 : tep->handle = handle;
368 0 : tep->time = PR_Now();
369 0 : tep->userData[0] = userData0;
370 0 : tep->userData[1] = userData1;
371 0 : tep->userData[2] = userData2;
372 0 : tep->userData[3] = userData3;
373 0 : tep->userData[4] = userData4;
374 0 : tep->userData[5] = userData5;
375 0 : tep->userData[6] = userData6;
376 0 : tep->userData[7] = userData7;
377 :
378 : /* When buffer segment is full, signal trace log thread to run */
379 0 : if (( mark % logEntriesPerSegment) == 0 )
380 : {
381 0 : PR_Lock( logLock );
382 0 : logCount++;
383 0 : PR_NotifyCondVar( logCVar );
384 0 : PR_Unlock( logLock );
385 : /*
386 : ** Gh0D! This is awful!
387 : ** Anyway, to minimize lost trace data segments,
388 : ** I inserted the PR_Sleep(0) to cause a context switch
389 : ** so that the log thread could run.
390 : ** I know, it perturbs the universe and may cause
391 : ** funny things to happen in the optimized builds.
392 : ** Take it out, lose data; leave it in risk Heisenberg.
393 : */
394 : /* PR_Sleep(0); */
395 : }
396 :
397 0 : return;
398 : } /* end PR_Trace() */
399 :
400 : /*
401 : **
402 : */
403 : PR_IMPLEMENT(void)
404 : PR_SetTraceOption(
405 : PRTraceOption command, /* One of the enumerated values */
406 : void *value /* command value or NULL */
407 : )
408 : {
409 : RName * rnp;
410 :
411 0 : switch ( command )
412 : {
413 : case PRTraceBufSize :
414 0 : PR_Lock( traceLock );
415 0 : PR_Free( tBuf );
416 0 : bufSize = *(PRInt32 *)value;
417 0 : NewTraceBuffer( bufSize );
418 0 : PR_Unlock( traceLock );
419 0 : PR_LOG( lm, PR_LOG_DEBUG,
420 : ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize));
421 0 : break;
422 :
423 : case PRTraceEnable :
424 0 : rnp = *(RName **)value;
425 0 : rnp->state = Running;
426 0 : PR_LOG( lm, PR_LOG_DEBUG,
427 : ("PRSetTraceOption: PRTraceEnable: %p", rnp));
428 0 : break;
429 :
430 : case PRTraceDisable :
431 0 : rnp = *(RName **)value;
432 0 : rnp->state = Suspended;
433 0 : PR_LOG( lm, PR_LOG_DEBUG,
434 : ("PRSetTraceOption: PRTraceDisable: %p", rnp));
435 0 : break;
436 :
437 : case PRTraceSuspend :
438 0 : traceState = Suspended;
439 0 : PR_LOG( lm, PR_LOG_DEBUG,
440 : ("PRSetTraceOption: PRTraceSuspend"));
441 0 : break;
442 :
443 : case PRTraceResume :
444 0 : traceState = Running;
445 0 : PR_LOG( lm, PR_LOG_DEBUG,
446 : ("PRSetTraceOption: PRTraceResume"));
447 0 : break;
448 :
449 : case PRTraceSuspendRecording :
450 0 : PR_Lock( logLock );
451 0 : logOrder = LogSuspend;
452 0 : PR_NotifyCondVar( logCVar );
453 0 : PR_Unlock( logLock );
454 0 : PR_LOG( lm, PR_LOG_DEBUG,
455 : ("PRSetTraceOption: PRTraceSuspendRecording"));
456 0 : break;
457 :
458 : case PRTraceResumeRecording :
459 0 : PR_LOG( lm, PR_LOG_DEBUG,
460 : ("PRSetTraceOption: PRTraceResumeRecording"));
461 0 : if ( logState != LogSuspend )
462 0 : break;
463 0 : PR_Lock( logLock );
464 0 : logOrder = LogResume;
465 0 : PR_NotifyCondVar( logCVar );
466 0 : PR_Unlock( logLock );
467 0 : break;
468 :
469 : case PRTraceStopRecording :
470 0 : PR_Lock( logLock );
471 0 : logOrder = LogStop;
472 0 : PR_NotifyCondVar( logCVar );
473 0 : PR_Unlock( logLock );
474 0 : PR_LOG( lm, PR_LOG_DEBUG,
475 : ("PRSetTraceOption: PRTraceStopRecording"));
476 0 : break;
477 :
478 : case PRTraceLockHandles :
479 0 : PR_LOG( lm, PR_LOG_DEBUG,
480 : ("PRSetTraceOption: PRTraceLockTraceHandles"));
481 0 : PR_Lock( traceLock );
482 0 : break;
483 :
484 : case PRTraceUnLockHandles :
485 0 : PR_LOG( lm, PR_LOG_DEBUG,
486 : ("PRSetTraceOption: PRTraceUnLockHandles"));
487 0 : PR_Unlock( traceLock );
488 0 : break;
489 :
490 : default:
491 0 : PR_LOG( lm, PR_LOG_ERROR,
492 : ("PRSetTraceOption: Invalid command %ld", command ));
493 0 : PR_ASSERT( 0 );
494 0 : break;
495 : } /* end switch() */
496 0 : return;
497 : } /* end PR_SetTraceOption() */
498 :
499 : /*
500 : **
501 : */
502 : PR_IMPLEMENT(void)
503 : PR_GetTraceOption(
504 : PRTraceOption command, /* One of the enumerated values */
505 : void *value /* command value or NULL */
506 : )
507 : {
508 0 : switch ( command )
509 : {
510 : case PRTraceBufSize :
511 0 : *((PRInt32 *)value) = bufSize;
512 0 : PR_LOG( lm, PR_LOG_DEBUG,
513 : ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize ));
514 0 : break;
515 :
516 : default:
517 0 : PR_LOG( lm, PR_LOG_ERROR,
518 : ("PRGetTraceOption: Invalid command %ld", command ));
519 0 : PR_ASSERT( 0 );
520 0 : break;
521 : } /* end switch() */
522 0 : return;
523 : } /* end PR_GetTraceOption() */
524 :
525 : /*
526 : **
527 : */
528 : PR_IMPLEMENT(PRTraceHandle)
529 : PR_GetTraceHandleFromName(
530 : const char *qName, /* QName search argument */
531 : const char *rName /* RName search argument */
532 : )
533 : {
534 : const char *qn, *rn, *desc;
535 0 : PRTraceHandle qh, rh = NULL;
536 0 : RName *rnp = NULL;
537 :
538 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t"
539 : "QName: %s, RName: %s", qName, rName ));
540 :
541 0 : qh = PR_FindNextTraceQname( NULL );
542 0 : while (qh != NULL)
543 : {
544 0 : rh = PR_FindNextTraceRname( NULL, qh );
545 0 : while ( rh != NULL )
546 : {
547 0 : PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc );
548 0 : if ( (strcmp( qName, qn ) == 0)
549 0 : && (strcmp( rName, rn ) == 0 ))
550 : {
551 0 : rnp = (RName *)rh;
552 0 : goto foundIt;
553 : }
554 0 : rh = PR_FindNextTraceRname( rh, qh );
555 : }
556 0 : qh = PR_FindNextTraceQname( NULL );
557 : }
558 :
559 : foundIt:
560 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
561 0 : return(rh);
562 : } /* end PR_GetTraceHandleFromName() */
563 :
564 : /*
565 : **
566 : */
567 : PR_IMPLEMENT(void)
568 : PR_GetTraceNameFromHandle(
569 : PRTraceHandle handle, /* handle as search argument */
570 : const char **qName, /* pointer to associated QName */
571 : const char **rName, /* pointer to associated RName */
572 : const char **description /* pointer to associated description */
573 : )
574 : {
575 0 : RName *rnp = (RName *)handle;
576 0 : QName *qnp = rnp->qName;
577 :
578 0 : *qName = qnp->name;
579 0 : *rName = rnp->name;
580 0 : *description = rnp->desc;
581 :
582 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetConterNameFromHandle: "
583 : "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s",
584 : qnp, rnp, qnp->name, rnp->name, rnp->desc ));
585 :
586 0 : return;
587 : } /* end PR_GetTraceNameFromHandle() */
588 :
589 : /*
590 : **
591 : */
592 : PR_IMPLEMENT(PRTraceHandle)
593 : PR_FindNextTraceQname(
594 : PRTraceHandle handle
595 : )
596 : {
597 0 : QName *qnp = (QName *)handle;
598 :
599 0 : if ( PR_CLIST_IS_EMPTY( &qNameList ))
600 0 : qnp = NULL;
601 0 : else if ( qnp == NULL )
602 0 : qnp = (QName *)PR_LIST_HEAD( &qNameList );
603 0 : else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList )
604 0 : qnp = NULL;
605 : else
606 0 : qnp = (QName *)PR_NEXT_LINK( &qnp->link );
607 :
608 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p",
609 : handle, qnp ));
610 :
611 0 : return((PRTraceHandle)qnp);
612 : } /* end PR_FindNextTraceQname() */
613 :
614 : /*
615 : **
616 : */
617 : PR_IMPLEMENT(PRTraceHandle)
618 : PR_FindNextTraceRname(
619 : PRTraceHandle rhandle,
620 : PRTraceHandle qhandle
621 : )
622 : {
623 0 : RName *rnp = (RName *)rhandle;
624 0 : QName *qnp = (QName *)qhandle;
625 :
626 :
627 0 : if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ))
628 0 : rnp = NULL;
629 0 : else if ( rnp == NULL )
630 0 : rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
631 0 : else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList )
632 0 : rnp = NULL;
633 : else
634 0 : rnp = (RName *)PR_NEXT_LINK( &rnp->link );
635 :
636 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p",
637 : rhandle, qhandle, rnp ));
638 :
639 0 : return((PRTraceHandle)rnp);
640 : } /* end PR_FindNextTraceRname() */
641 :
642 : /*
643 : **
644 : */
645 0 : static PRFileDesc * InitializeRecording( void )
646 : {
647 : char *logFileName;
648 : PRFileDesc *logFile;
649 :
650 : /* Self initialize, if necessary */
651 0 : if ( traceLock == NULL )
652 0 : _PR_InitializeTrace();
653 :
654 0 : PR_LOG( lm, PR_LOG_DEBUG,
655 : ("PR_RecordTraceEntries: begins"));
656 :
657 0 : logLostData = 0; /* reset at entry */
658 0 : logState = LogReset;
659 :
660 : /* Get the filename for the logfile from the environment */
661 0 : logFileName = PR_GetEnvSecure( "NSPR_TRACE_LOG" );
662 0 : if ( logFileName == NULL )
663 : {
664 0 : PR_LOG( lm, PR_LOG_ERROR,
665 : ("RecordTraceEntries: Environment variable not defined. Exiting"));
666 0 : return NULL;
667 : }
668 :
669 : /* Open the logfile */
670 0 : logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 );
671 0 : if ( logFile == NULL )
672 : {
673 0 : PR_LOG( lm, PR_LOG_ERROR,
674 : ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld",
675 : logFileName, PR_GetOSError()));
676 0 : return NULL;
677 : }
678 0 : return logFile;
679 : } /* end InitializeRecording() */
680 :
681 : /*
682 : **
683 : */
684 0 : static void ProcessOrders( void )
685 : {
686 0 : switch ( logOrder )
687 : {
688 : case LogReset :
689 0 : logOrder = logState = localState;
690 0 : PR_LOG( lm, PR_LOG_DEBUG,
691 : ("RecordTraceEntries: LogReset"));
692 0 : break;
693 :
694 : case LogSuspend :
695 0 : localState = logOrder = logState = LogSuspend;
696 0 : PR_LOG( lm, PR_LOG_DEBUG,
697 : ("RecordTraceEntries: LogSuspend"));
698 0 : break;
699 :
700 : case LogResume :
701 0 : localState = logOrder = logState = LogActive;
702 0 : PR_LOG( lm, PR_LOG_DEBUG,
703 : ("RecordTraceEntries: LogResume"));
704 0 : break;
705 :
706 : case LogStop :
707 0 : logOrder = logState = LogStop;
708 0 : PR_LOG( lm, PR_LOG_DEBUG,
709 : ("RecordTraceEntries: LogStop"));
710 0 : break;
711 :
712 : default :
713 0 : PR_LOG( lm, PR_LOG_ERROR,
714 : ("RecordTraceEntries: Invalid logOrder: %ld", logOrder ));
715 0 : PR_ASSERT( 0 );
716 0 : break;
717 : } /* end switch() */
718 0 : return ;
719 : } /* end ProcessOrders() */
720 :
721 : /*
722 : **
723 : */
724 0 : static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount )
725 : {
726 : PRInt32 rc;
727 :
728 :
729 0 : PR_LOG( lm, PR_LOG_ERROR,
730 : ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount));
731 0 : rc = PR_Write( logFile, buf , amount );
732 0 : if ( rc == -1 )
733 0 : PR_LOG( lm, PR_LOG_ERROR,
734 : ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() ));
735 0 : else if ( rc != amount )
736 0 : PR_LOG( lm, PR_LOG_ERROR,
737 : ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount, rc));
738 : else
739 0 : PR_LOG( lm, PR_LOG_DEBUG,
740 : ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount));
741 :
742 0 : return;
743 : } /* end WriteTraceSegment() */
744 :
745 : /*
746 : **
747 : */
748 : PR_IMPLEMENT(void)
749 : PR_RecordTraceEntries(
750 : void
751 : )
752 : {
753 : PRFileDesc *logFile;
754 : PRInt32 lostSegments;
755 0 : PRInt32 currentSegment = 0;
756 : void *buf;
757 : PRBool doWrite;
758 :
759 0 : logFile = InitializeRecording();
760 0 : if ( logFile == NULL )
761 : {
762 0 : PR_LOG( lm, PR_LOG_DEBUG,
763 : ("PR_RecordTraceEntries: Failed to initialize"));
764 0 : return;
765 : }
766 :
767 : /* Do this until told to stop */
768 0 : while ( logState != LogStop )
769 : {
770 :
771 0 : PR_Lock( logLock );
772 :
773 0 : while ( (logCount == 0) && ( logOrder == logState ) )
774 0 : PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT );
775 :
776 : /* Handle state transitions */
777 0 : if ( logOrder != logState )
778 0 : ProcessOrders();
779 :
780 : /* recalculate local controls */
781 0 : if ( logCount )
782 : {
783 0 : lostSegments = logCount - logSegments;
784 0 : if ( lostSegments > 0 )
785 : {
786 0 : logLostData += ( logCount - logSegments );
787 0 : logCount = (logCount % logSegments);
788 0 : currentSegment = logCount;
789 0 : PR_LOG( lm, PR_LOG_DEBUG,
790 : ("PR_RecordTraceEntries: LostData segments: %ld", logLostData));
791 : }
792 : else
793 : {
794 0 : logCount--;
795 : }
796 :
797 0 : buf = tBuf + ( logEntriesPerSegment * currentSegment );
798 0 : if (++currentSegment >= logSegments )
799 0 : currentSegment = 0;
800 0 : doWrite = PR_TRUE;
801 : }
802 : else
803 0 : doWrite = PR_FALSE;
804 :
805 0 : PR_Unlock( logLock );
806 :
807 0 : if ( doWrite == PR_TRUE )
808 : {
809 0 : if ( localState != LogSuspend )
810 0 : WriteTraceSegment( logFile, buf, logSegSize );
811 : else
812 0 : PR_LOG( lm, PR_LOG_DEBUG,
813 : ("RecordTraceEntries: PR_Write(): is suspended" ));
814 : }
815 :
816 : } /* end while(logState...) */
817 :
818 0 : PR_Close( logFile );
819 0 : PR_LOG( lm, PR_LOG_DEBUG,
820 : ("RecordTraceEntries: exiting"));
821 0 : return;
822 : } /* end PR_RecordTraceEntries() */
823 :
824 : /*
825 : **
826 : */
827 : PR_IMPLEMENT(PRIntn)
828 : PR_GetTraceEntries(
829 : PRTraceEntry *buffer, /* where to write output */
830 : PRInt32 count, /* number to get */
831 : PRInt32 *found /* number you got */
832 : )
833 : {
834 : PRInt32 rc;
835 0 : PRInt32 copied = 0;
836 :
837 0 : PR_Lock( traceLock );
838 :
839 : /*
840 : ** Depending on where the LastSeen and Next indices are,
841 : ** copy the trace buffer in one or two pieces.
842 : */
843 0 : PR_LOG( lm, PR_LOG_ERROR,
844 : ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen));
845 :
846 0 : if ( fetchLastSeen <= next )
847 : {
848 0 : while (( count-- > 0 ) && (fetchLastSeen < next ))
849 : {
850 0 : *(buffer + copied++) = *(tBuf + fetchLastSeen++);
851 : }
852 0 : PR_LOG( lm, PR_LOG_ERROR,
853 : ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
854 : }
855 : else /* copy in 2 parts */
856 : {
857 0 : while ( count-- > 0 && fetchLastSeen <= last )
858 : {
859 0 : *(buffer + copied++) = *(tBuf + fetchLastSeen++);
860 : }
861 0 : fetchLastSeen = 0;
862 :
863 0 : PR_LOG( lm, PR_LOG_ERROR,
864 : ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
865 :
866 0 : while ( count-- > 0 && fetchLastSeen < next )
867 : {
868 0 : *(buffer + copied++) = *(tBuf + fetchLastSeen++);
869 : }
870 0 : PR_LOG( lm, PR_LOG_ERROR,
871 : ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
872 : }
873 :
874 0 : *found = copied;
875 0 : rc = ( fetchLostData == PR_TRUE )? 1 : 0;
876 0 : fetchLostData = PR_FALSE;
877 :
878 0 : PR_Unlock( traceLock );
879 0 : return rc;
880 : } /* end PR_GetTraceEntries() */
881 :
882 : /* end prtrace.c */
|