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