nsprpub/pr/src/misc/prtrace.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 /*
     7 ** prtrace.c -- NSPR Trace Instrumentation
     8 **
     9 ** Implement the API defined in prtrace.h
    10 **
    11 **
    12 **
    13 */
    15 #include <string.h>
    16 #include "primpl.h"
    19 #define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 )
    20 #define DEFAULT_BUFFER_SEGMENTS    2
    22 /*
    23 ** Enumerate states in a RName structure
    24 */
    25 typedef enum TraceState
    26 {
    27     Running = 1,
    28     Suspended = 2
    29 } TraceState;
    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;
    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;
    55 /*
    56 ** The Trace Facility database
    57 **
    58 */
    59 static PRLogModuleInfo *lm;
    61 static PRLock      *traceLock;      /* Facility Lock */
    62 static PRCList     qNameList;       /* anchor to all QName structures */
    63 static TraceState traceState = Running;
    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 */
    73 /*
    74 ** Real-time buffer capture controls
    75 */
    76 static PRInt32 fetchLastSeen = 0;
    77 static PRBool  fetchLostData = PR_FALSE;
    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 */
   109 /*
   110 ** end Trace Database
   111 **
   112 */
   114 /*
   115 ** _PR_InitializeTrace() -- Initialize the trace facility
   116 */
   117 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     logSegments = DEFAULT_BUFFER_SEGMENTS;
   125     logEntries = size / sizeof(PRTraceEntry);
   126     logEntriesPerSegment = logEntries / logSegments;
   127     logEntries = logSegments * logEntriesPerSegment;
   128     bufSize = logEntries * sizeof(PRTraceEntry);
   129     logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry);
   130     PR_ASSERT( bufSize != 0);
   131     PR_LOG( lm, PR_LOG_ERROR,
   132         ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld",
   133             logSegments, logEntries, logEntriesPerSegment, logSegSize ));
   136     tBuf = PR_Malloc( bufSize );
   137     if ( tBuf == NULL )
   138     {
   139         PR_LOG( lm, PR_LOG_ERROR,
   140             ("PRTrace: Failed to get trace buffer"));
   141         PR_ASSERT( 0 );
   142     } 
   143     else
   144     {
   145         PR_LOG( lm, PR_LOG_NOTICE,
   146             ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf));
   147     }
   149     next = 0;
   150     last = logEntries -1;
   151     logCount = 0;
   152     logLostData = PR_TRUE; /* not really on first call */
   153     logOrder = LogReset;
   155 } /* end NewTraceBuffer() */
   157 /*
   158 ** _PR_InitializeTrace() -- Initialize the trace facility
   159 */
   160 static void _PR_InitializeTrace( void )
   161 {
   162     /* The lock pointer better be null on this call */
   163     PR_ASSERT( traceLock == NULL );
   165     traceLock = PR_NewLock();
   166     PR_ASSERT( traceLock != NULL );
   168     PR_Lock( traceLock );
   170     PR_INIT_CLIST( &qNameList );
   172     lm = PR_NewLogModule("trace");
   174     bufSize = DEFAULT_TRACE_BUFSIZE;
   175     NewTraceBuffer( bufSize );
   177     /* Initialize logging controls */
   178     logLock = PR_NewLock();
   179     logCVar = PR_NewCondVar( logLock );
   181     PR_Unlock( traceLock );
   182     return;    
   183 } /* end _PR_InitializeTrace() */
   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     PRBool  matchQname = PR_FALSE;
   199     /* Self initialize, if necessary */
   200     if ( traceLock == NULL )
   201         _PR_InitializeTrace();
   203     /* Validate input arguments */
   204     PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX );
   205     PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX );
   206     PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX );
   208     PR_LOG( lm, PR_LOG_DEBUG,
   209             ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName));
   211     /* Lock the Facility */
   212     PR_Lock( traceLock );
   214     /* Do we already have a matching QName? */
   215     if (!PR_CLIST_IS_EMPTY( &qNameList ))
   216     {
   217         qnp = (QName *) PR_LIST_HEAD( &qNameList );
   218         do {
   219             if ( strcmp(qnp->name, qName) == 0)
   220             {
   221                 matchQname = PR_TRUE;
   222                 break;
   223             }
   224             qnp = (QName *)PR_NEXT_LINK( &qnp->link );
   225         } 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     if ( matchQname != PR_TRUE )
   234     {
   235         qnp = PR_NEWZAP( QName );
   236         PR_ASSERT( qnp != NULL );
   237         PR_INIT_CLIST( &qnp->link ); 
   238         PR_INIT_CLIST( &qnp->rNameList ); 
   239         strcpy( qnp->name, qName );
   240         PR_APPEND_LINK( &qnp->link, &qNameList ); 
   241     }
   243     /* Do we already have a matching RName? */
   244     if (!PR_CLIST_IS_EMPTY( &qnp->rNameList ))
   245     {
   246         rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList );
   247         do {
   248             /*
   249             ** No duplicate RNames are allowed within a QName
   250             **
   251             */
   252             PR_ASSERT( strcmp(rnp->name, rName));
   253             rnp = (RName *)PR_NEXT_LINK( &rnp->link );
   254         } while( rnp != (RName *)&qnp->rNameList );
   255     }
   257     /* Get a new RName structure; initialize its members */
   258     rnp = PR_NEWZAP( RName );
   259     PR_ASSERT( rnp != NULL );
   260     PR_INIT_CLIST( &rnp->link );
   261     strcpy( rnp->name, rName );
   262     strcpy( rnp->desc, description );
   263     rnp->lock = PR_NewLock();
   264     rnp->state = Running;
   265     if ( rnp->lock == NULL )
   266     {
   267         PR_ASSERT(0);
   268     }
   270     PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */    
   271     rnp->qName = qnp;                       /* point the RName to the QName */
   273     /* Unlock the Facility */
   274     PR_Unlock( traceLock );
   275     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t",
   276         qName, qnp, rName, rnp ));
   278     return((PRTraceHandle)rnp);
   279 } /* end  PR_CreateTrace() */
   281 /*
   282 **
   283 */
   284 PR_IMPLEMENT(void) 
   285 	PR_DestroyTrace( 
   286 		PRTraceHandle handle    /* Handle to be destroyed */
   287 )
   288 {
   289     RName   *rnp = (RName *)handle;
   290     QName   *qnp = rnp->qName;
   292     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", 
   293         qnp->name, rnp->name));
   295     /* Lock the Facility */
   296     PR_Lock( traceLock );
   298     /*
   299     ** Remove RName from the list of RNames in QName
   300     ** and free RName
   301     */
   302     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", 
   303         rnp->name, rnp));
   304     PR_REMOVE_LINK( &rnp->link );
   305     PR_Free( rnp->lock );
   306     PR_DELETE( rnp );
   308     /*
   309     ** If this is the last RName within QName
   310     **   remove QName from the qNameList and free it
   311     */
   312     if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) )
   313     {
   314         PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", 
   315             qnp->name, qnp));
   316         PR_REMOVE_LINK( &qnp->link );
   317         PR_DELETE( qnp );
   318     } 
   320     /* Unlock the Facility */
   321     PR_Unlock( traceLock );
   322     return;
   323 } /* end PR_DestroyTrace()  */
   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;
   344     if ( (traceState == Suspended ) 
   345         || ( ((RName *)handle)->state == Suspended )) 
   346         return;
   348     /*
   349     ** Get the next trace entry slot w/ minimum delay
   350     */
   351     PR_Lock( traceLock );
   353     tep = &tBuf[next++]; 
   354     if ( next > last )
   355         next = 0;
   356     if ( fetchLostData == PR_FALSE && next == fetchLastSeen )
   357         fetchLostData = PR_TRUE;
   359     mark = next;
   361     PR_Unlock( traceLock );
   363     /*
   364     ** We have a trace entry. Fill it in.
   365     */
   366     tep->thread = PR_GetCurrentThread();
   367     tep->handle = handle;
   368     tep->time   = PR_Now();
   369     tep->userData[0] = userData0;
   370     tep->userData[1] = userData1;
   371     tep->userData[2] = userData2;
   372     tep->userData[3] = userData3;
   373     tep->userData[4] = userData4;
   374     tep->userData[5] = userData5;
   375     tep->userData[6] = userData6;
   376     tep->userData[7] = userData7;
   378     /* When buffer segment is full, signal trace log thread to run */
   379     if (( mark % logEntriesPerSegment) == 0 )
   380     {
   381         PR_Lock( logLock );
   382         logCount++;
   383         PR_NotifyCondVar( logCVar );
   384         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     }
   397     return;
   398 } /* end PR_Trace() */
   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;
   411     switch ( command )
   412     {
   413         case PRTraceBufSize :
   414             PR_Lock( traceLock );
   415             PR_Free( tBuf );
   416             bufSize = *(PRInt32 *)value;
   417             NewTraceBuffer( bufSize );
   418             PR_Unlock( traceLock );
   419             PR_LOG( lm, PR_LOG_DEBUG,
   420                 ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize));
   421             break;
   423         case PRTraceEnable :
   424             rnp = *(RName **)value;
   425             rnp->state = Running;
   426             PR_LOG( lm, PR_LOG_DEBUG,
   427                 ("PRSetTraceOption: PRTraceEnable: %p", rnp));
   428             break;
   430         case PRTraceDisable :
   431             rnp = *(RName **)value;
   432             rnp->state = Suspended;
   433             PR_LOG( lm, PR_LOG_DEBUG,
   434                 ("PRSetTraceOption: PRTraceDisable: %p", rnp));
   435             break;
   437         case PRTraceSuspend :
   438             traceState = Suspended;
   439             PR_LOG( lm, PR_LOG_DEBUG,
   440                 ("PRSetTraceOption: PRTraceSuspend"));
   441             break;
   443         case PRTraceResume :
   444             traceState = Running;
   445             PR_LOG( lm, PR_LOG_DEBUG,
   446                 ("PRSetTraceOption: PRTraceResume"));
   447             break;
   449         case PRTraceSuspendRecording :
   450             PR_Lock( logLock );
   451             logOrder = LogSuspend;
   452             PR_NotifyCondVar( logCVar );
   453             PR_Unlock( logLock );
   454             PR_LOG( lm, PR_LOG_DEBUG,
   455                 ("PRSetTraceOption: PRTraceSuspendRecording"));
   456             break;
   458         case PRTraceResumeRecording :
   459             PR_LOG( lm, PR_LOG_DEBUG,
   460                 ("PRSetTraceOption: PRTraceResumeRecording"));
   461             if ( logState != LogSuspend )
   462                 break;
   463             PR_Lock( logLock );
   464             logOrder = LogResume;
   465             PR_NotifyCondVar( logCVar );
   466             PR_Unlock( logLock );
   467             break;
   469         case PRTraceStopRecording :
   470             PR_Lock( logLock );
   471             logOrder = LogStop;
   472             PR_NotifyCondVar( logCVar );
   473             PR_Unlock( logLock );
   474             PR_LOG( lm, PR_LOG_DEBUG,
   475                 ("PRSetTraceOption: PRTraceStopRecording"));
   476             break;
   478         case PRTraceLockHandles :
   479             PR_LOG( lm, PR_LOG_DEBUG,
   480                 ("PRSetTraceOption: PRTraceLockTraceHandles"));
   481             PR_Lock( traceLock );
   482             break;
   484         case PRTraceUnLockHandles :
   485             PR_LOG( lm, PR_LOG_DEBUG,
   486                 ("PRSetTraceOption: PRTraceUnLockHandles"));
   487             PR_Unlock( traceLock );
   488             break;
   490         default:
   491             PR_LOG( lm, PR_LOG_ERROR,
   492                 ("PRSetTraceOption: Invalid command %ld", command ));
   493             PR_ASSERT( 0 );
   494             break;
   495     } /* end switch() */
   496     return;
   497 } /* end  PR_SetTraceOption() */
   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     switch ( command )
   509     {
   510         case PRTraceBufSize :
   511             *((PRInt32 *)value) = bufSize;
   512             PR_LOG( lm, PR_LOG_DEBUG,
   513                 ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize ));
   514             break;
   516         default:
   517             PR_LOG( lm, PR_LOG_ERROR,
   518                 ("PRGetTraceOption: Invalid command %ld", command ));
   519             PR_ASSERT( 0 );
   520             break;
   521     } /* end switch() */
   522     return;
   523 } /* end PR_GetTraceOption() */
   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     PRTraceHandle     qh, rh = NULL;
   536     RName   *rnp = NULL;
   538     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t"
   539         "QName: %s, RName: %s", qName, rName ));
   541     qh = PR_FindNextTraceQname( NULL );
   542     while (qh != NULL)
   543     {
   544         rh = PR_FindNextTraceRname( NULL, qh );
   545         while ( rh != NULL )
   546         {
   547             PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc );
   548             if ( (strcmp( qName, qn ) == 0)
   549                 && (strcmp( rName, rn ) == 0 ))
   550             {
   551                 rnp = (RName *)rh;
   552                 goto foundIt;
   553             }
   554             rh = PR_FindNextTraceRname( rh, qh );
   555         }
   556         qh = PR_FindNextTraceQname( NULL );
   557     }
   559 foundIt:
   560     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
   561     return(rh);
   562 } /* end PR_GetTraceHandleFromName() */
   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     RName   *rnp = (RName *)handle;
   576     QName   *qnp = rnp->qName;
   578     *qName = qnp->name;
   579     *rName = rnp->name;
   580     *description = rnp->desc;
   582     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 ));
   586     return;
   587 } /* end PR_GetTraceNameFromHandle() */
   589 /*
   590 **
   591 */
   592 PR_IMPLEMENT(PRTraceHandle) 
   593 	PR_FindNextTraceQname( 
   594         PRTraceHandle handle
   595 )
   596 {
   597     QName *qnp = (QName *)handle;
   599     if ( PR_CLIST_IS_EMPTY( &qNameList ))
   600             qnp = NULL;
   601     else if ( qnp == NULL )
   602         qnp = (QName *)PR_LIST_HEAD( &qNameList );
   603     else if ( PR_NEXT_LINK( &qnp->link ) ==  &qNameList )
   604         qnp = NULL;
   605     else  
   606         qnp = (QName *)PR_NEXT_LINK( &qnp->link );
   608     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p", 
   609         handle, qnp ));
   611     return((PRTraceHandle)qnp);
   612 } /* end PR_FindNextTraceQname() */
   614 /*
   615 **
   616 */
   617 PR_IMPLEMENT(PRTraceHandle) 
   618 	PR_FindNextTraceRname( 
   619         PRTraceHandle rhandle,
   620         PRTraceHandle qhandle
   621 )
   622 {
   623     RName *rnp = (RName *)rhandle;
   624     QName *qnp = (QName *)qhandle;
   627     if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ))
   628         rnp = NULL;
   629     else if ( rnp == NULL )
   630         rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
   631     else if ( PR_NEXT_LINK( &rnp->link ) ==  &qnp->rNameList )
   632         rnp = NULL;
   633     else
   634         rnp = (RName *)PR_NEXT_LINK( &rnp->link );
   636     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 
   637         rhandle, qhandle, rnp ));
   639     return((PRTraceHandle)rnp);
   640 } /* end PR_FindNextTraceRname() */
   642 /*
   643 **
   644 */
   645 static PRFileDesc * InitializeRecording( void )
   646 {
   647     char    *logFileName;
   648     PRFileDesc  *logFile;
   650     /* Self initialize, if necessary */
   651     if ( traceLock == NULL )
   652         _PR_InitializeTrace();
   654     PR_LOG( lm, PR_LOG_DEBUG,
   655         ("PR_RecordTraceEntries: begins"));
   657     logLostData = 0; /* reset at entry */
   658     logState = LogReset;
   660 #ifdef XP_UNIX
   661     if ((getuid() != geteuid()) || (getgid() != getegid())) {
   662         return NULL;
   663     }
   664 #endif /* XP_UNIX */
   666     /* Get the filename for the logfile from the environment */
   667     logFileName = PR_GetEnv( "NSPR_TRACE_LOG" );
   668     if ( logFileName == NULL )
   669     {
   670         PR_LOG( lm, PR_LOG_ERROR,
   671             ("RecordTraceEntries: Environment variable not defined. Exiting"));
   672         return NULL;
   673     }
   675     /* Open the logfile */
   676     logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 );
   677     if ( logFile == NULL )
   678     {
   679         PR_LOG( lm, PR_LOG_ERROR,
   680             ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld", 
   681 		logFileName, PR_GetOSError()));
   682         return NULL;
   683     }
   684     return logFile;
   685 } /* end InitializeRecording() */
   687 /*
   688 **
   689 */
   690 static void ProcessOrders( void )
   691 {
   692     switch ( logOrder )
   693     {
   694     case LogReset :
   695         logOrder = logState = localState;
   696         PR_LOG( lm, PR_LOG_DEBUG,
   697             ("RecordTraceEntries: LogReset"));
   698         break;
   700     case LogSuspend :
   701         localState = logOrder = logState = LogSuspend;
   702         PR_LOG( lm, PR_LOG_DEBUG,
   703             ("RecordTraceEntries: LogSuspend"));
   704         break;
   706     case LogResume :
   707         localState = logOrder = logState = LogActive;
   708         PR_LOG( lm, PR_LOG_DEBUG,
   709             ("RecordTraceEntries: LogResume"));
   710         break;
   712     case LogStop :
   713         logOrder = logState = LogStop;
   714         PR_LOG( lm, PR_LOG_DEBUG,
   715             ("RecordTraceEntries: LogStop"));
   716         break;
   718     default :
   719         PR_LOG( lm, PR_LOG_ERROR,
   720             ("RecordTraceEntries: Invalid logOrder: %ld", logOrder ));
   721         PR_ASSERT( 0 );
   722         break;
   723     } /* end switch() */
   724     return ;
   725 } /* end ProcessOrders() */
   727 /*
   728 **
   729 */
   730 static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount )
   731 {
   732     PRInt32 rc;
   735     PR_LOG( lm, PR_LOG_ERROR,
   736         ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount));
   737     rc = PR_Write( logFile, buf , amount );
   738     if ( rc == -1 )
   739         PR_LOG( lm, PR_LOG_ERROR,
   740             ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() ));
   741     else if ( rc != amount )
   742         PR_LOG( lm, PR_LOG_ERROR,
   743             ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount, rc));
   744     else 
   745         PR_LOG( lm, PR_LOG_DEBUG,
   746             ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount));
   748     return;
   749 } /* end WriteTraceSegment() */
   751 /*
   752 **
   753 */
   754 PR_IMPLEMENT(void)
   755 	PR_RecordTraceEntries(
   756         void 
   757 )
   758 {
   759     PRFileDesc  *logFile;
   760     PRInt32     lostSegments;
   761     PRInt32     currentSegment = 0;
   762     void        *buf;
   763     PRBool      doWrite;
   765     logFile = InitializeRecording();
   766     if ( logFile == NULL )
   767     {
   768         PR_LOG( lm, PR_LOG_DEBUG,
   769             ("PR_RecordTraceEntries: Failed to initialize"));
   770         return;
   771     }
   773     /* Do this until told to stop */
   774     while ( logState != LogStop )
   775     {
   777         PR_Lock( logLock );
   779         while ( (logCount == 0) && ( logOrder == logState ) )
   780             PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT );
   782         /* Handle state transitions */
   783         if ( logOrder != logState )
   784             ProcessOrders();
   786         /* recalculate local controls */
   787         if ( logCount )
   788         {
   789             lostSegments = logCount - logSegments;
   790             if ( lostSegments > 0 )
   791             {
   792                 logLostData += ( logCount - logSegments );
   793                 logCount = (logCount % logSegments);
   794                 currentSegment = logCount;
   795                 PR_LOG( lm, PR_LOG_DEBUG,
   796                     ("PR_RecordTraceEntries: LostData segments: %ld", logLostData));
   797             }
   798             else
   799             {
   800                 logCount--;
   801             }
   803             buf = tBuf + ( logEntriesPerSegment * currentSegment );
   804             if (++currentSegment >= logSegments )
   805                 currentSegment = 0;
   806             doWrite = PR_TRUE;
   807         }
   808         else
   809             doWrite = PR_FALSE;
   811         PR_Unlock( logLock );
   813         if ( doWrite == PR_TRUE )
   814         {
   815             if ( localState != LogSuspend )
   816                 WriteTraceSegment( logFile, buf, logSegSize );
   817             else
   818                 PR_LOG( lm, PR_LOG_DEBUG,
   819                     ("RecordTraceEntries: PR_Write(): is suspended" ));
   820         }
   822     } /* end while(logState...) */
   824     PR_Close( logFile );
   825     PR_LOG( lm, PR_LOG_DEBUG,
   826         ("RecordTraceEntries: exiting"));
   827     return;
   828 } /* end  PR_RecordTraceEntries() */
   830 /*
   831 **
   832 */
   833 PR_IMPLEMENT(PRIntn)
   834     PR_GetTraceEntries(
   835         PRTraceEntry    *buffer,    /* where to write output */
   836         PRInt32         count,      /* number to get */
   837         PRInt32         *found      /* number you got */
   838 )
   839 {
   840     PRInt32 rc; 
   841     PRInt32 copied = 0;
   843     PR_Lock( traceLock );
   845     /*
   846     ** Depending on where the LastSeen and Next indices are,
   847     ** copy the trace buffer in one or two pieces. 
   848     */
   849     PR_LOG( lm, PR_LOG_ERROR,
   850         ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen));
   852     if ( fetchLastSeen <= next )
   853     {
   854         while (( count-- > 0 ) && (fetchLastSeen < next ))
   855         {
   856             *(buffer + copied++) = *(tBuf + fetchLastSeen++);
   857         }
   858         PR_LOG( lm, PR_LOG_ERROR,
   859             ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
   860     }
   861     else /* copy in 2 parts */
   862     {
   863         while ( count-- > 0  && fetchLastSeen <= last )
   864         {
   865             *(buffer + copied++) = *(tBuf + fetchLastSeen++);
   866         }
   867         fetchLastSeen = 0;
   869         PR_LOG( lm, PR_LOG_ERROR,
   870             ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
   872         while ( count-- > 0  && fetchLastSeen < next )
   873         {
   874             *(buffer + copied++) = *(tBuf + fetchLastSeen++);
   875         }
   876         PR_LOG( lm, PR_LOG_ERROR,
   877             ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
   878     }
   880     *found = copied;
   881     rc = ( fetchLostData == PR_TRUE )? 1 : 0;
   882     fetchLostData = PR_FALSE;
   884     PR_Unlock( traceLock );
   885     return rc;
   886 } /* end PR_GetTraceEntries() */
   888 /* end prtrace.c */

mercurial