nsprpub/pr/src/misc/prtrace.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/misc/prtrace.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,888 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +** prtrace.c -- NSPR Trace Instrumentation
    1.11 +**
    1.12 +** Implement the API defined in prtrace.h
    1.13 +**
    1.14 +**
    1.15 +**
    1.16 +*/
    1.17 +
    1.18 +#include <string.h>
    1.19 +#include "primpl.h"
    1.20 +
    1.21 +
    1.22 +#define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 )
    1.23 +#define DEFAULT_BUFFER_SEGMENTS    2
    1.24 +
    1.25 +/*
    1.26 +** Enumerate states in a RName structure
    1.27 +*/
    1.28 +typedef enum TraceState
    1.29 +{
    1.30 +    Running = 1,
    1.31 +    Suspended = 2
    1.32 +} TraceState;
    1.33 +
    1.34 +/*
    1.35 +** Define QName structure
    1.36 +*/
    1.37 +typedef struct QName
    1.38 +{
    1.39 +    PRCList link;
    1.40 +    PRCList rNameList;
    1.41 +    char    name[PRTRACE_NAME_MAX+1];
    1.42 +} QName;
    1.43 +
    1.44 +/*
    1.45 +** Define RName structure
    1.46 +*/
    1.47 +typedef struct RName
    1.48 +{
    1.49 +    PRCList link;
    1.50 +    PRLock  *lock;
    1.51 +    QName   *qName;
    1.52 +    TraceState state;
    1.53 +    char    name[PRTRACE_NAME_MAX+1];
    1.54 +    char    desc[PRTRACE_DESC_MAX+1];
    1.55 +} RName;
    1.56 +
    1.57 +
    1.58 +/*
    1.59 +** The Trace Facility database
    1.60 +**
    1.61 +*/
    1.62 +static PRLogModuleInfo *lm;
    1.63 +
    1.64 +static PRLock      *traceLock;      /* Facility Lock */
    1.65 +static PRCList     qNameList;       /* anchor to all QName structures */
    1.66 +static TraceState traceState = Running;
    1.67 +
    1.68 +/*
    1.69 +** in-memory trace buffer controls
    1.70 +*/
    1.71 +static  PRTraceEntry    *tBuf;      /* pointer to buffer */
    1.72 +static  PRInt32         bufSize;    /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */
    1.73 +static  volatile PRInt32  next;     /* index to next PRTraceEntry */
    1.74 +static  PRInt32         last;       /* index of highest numbered trace entry */
    1.75 +
    1.76 +/*
    1.77 +** Real-time buffer capture controls
    1.78 +*/
    1.79 +static PRInt32 fetchLastSeen = 0;
    1.80 +static PRBool  fetchLostData = PR_FALSE;
    1.81 +
    1.82 +/*
    1.83 +** Buffer write-to-file controls
    1.84 +*/
    1.85 +static  PRLock      *logLock;               /* Sync lock */
    1.86 +static  PRCondVar   *logCVar;               /* Sync Condidtion Variable */
    1.87 +/*
    1.88 +** Inter-thread state communication.
    1.89 +** Controling thread writes to logOrder under protection of logCVar
    1.90 +** the logging thread reads logOrder and sets logState on Notify.
    1.91 +** 
    1.92 +** logSegments, logCount, logLostData must be read and written under
    1.93 +** protection of logLock, logCVar.
    1.94 +** 
    1.95 +*/
    1.96 +static  enum LogState
    1.97 +{
    1.98 +    LogNotRunning,  /* Initial state */
    1.99 +    LogReset,       /* Causes logger to re-calc controls */
   1.100 +    LogActive,      /* Logging in progress, set only by log thread */
   1.101 +    LogSuspend,     /* Suspend Logging */ 
   1.102 +    LogResume,      /* Resume Logging => LogActive */ 
   1.103 +    LogStop         /* Stop the log thread */
   1.104 +}   logOrder, logState, localState;         /* controlling state variables */
   1.105 +static  PRInt32     logSegments;            /* Number of buffer segments */
   1.106 +static  PRInt32     logEntries;             /* number of Trace Entries in the buffer */
   1.107 +static  PRInt32     logEntriesPerSegment;   /* number of PRTraceEntries per buffer segment */
   1.108 +static  PRInt32     logSegSize;             /* size of buffer segment */
   1.109 +static  PRInt32     logCount;               /* number of segments pending output */
   1.110 +static  PRInt32     logLostData;            /* number of lost log buffer segments */
   1.111 +
   1.112 +/*
   1.113 +** end Trace Database
   1.114 +**
   1.115 +*/
   1.116 +
   1.117 +/*
   1.118 +** _PR_InitializeTrace() -- Initialize the trace facility
   1.119 +*/
   1.120 +static void NewTraceBuffer( PRInt32 size )
   1.121 +{
   1.122 +    /*
   1.123 +    ** calculate the size of the buffer
   1.124 +    ** round down so that each segment has the same number of
   1.125 +    ** trace entries
   1.126 +    */
   1.127 +    logSegments = DEFAULT_BUFFER_SEGMENTS;
   1.128 +    logEntries = size / sizeof(PRTraceEntry);
   1.129 +    logEntriesPerSegment = logEntries / logSegments;
   1.130 +    logEntries = logSegments * logEntriesPerSegment;
   1.131 +    bufSize = logEntries * sizeof(PRTraceEntry);
   1.132 +    logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry);
   1.133 +    PR_ASSERT( bufSize != 0);
   1.134 +    PR_LOG( lm, PR_LOG_ERROR,
   1.135 +        ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld",
   1.136 +            logSegments, logEntries, logEntriesPerSegment, logSegSize ));
   1.137 +
   1.138 +
   1.139 +    tBuf = PR_Malloc( bufSize );
   1.140 +    if ( tBuf == NULL )
   1.141 +    {
   1.142 +        PR_LOG( lm, PR_LOG_ERROR,
   1.143 +            ("PRTrace: Failed to get trace buffer"));
   1.144 +        PR_ASSERT( 0 );
   1.145 +    } 
   1.146 +    else
   1.147 +    {
   1.148 +        PR_LOG( lm, PR_LOG_NOTICE,
   1.149 +            ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf));
   1.150 +    }
   1.151 +
   1.152 +    next = 0;
   1.153 +    last = logEntries -1;
   1.154 +    logCount = 0;
   1.155 +    logLostData = PR_TRUE; /* not really on first call */
   1.156 +    logOrder = LogReset;
   1.157 +
   1.158 +} /* end NewTraceBuffer() */
   1.159 +
   1.160 +/*
   1.161 +** _PR_InitializeTrace() -- Initialize the trace facility
   1.162 +*/
   1.163 +static void _PR_InitializeTrace( void )
   1.164 +{
   1.165 +    /* The lock pointer better be null on this call */
   1.166 +    PR_ASSERT( traceLock == NULL );
   1.167 +
   1.168 +    traceLock = PR_NewLock();
   1.169 +    PR_ASSERT( traceLock != NULL );
   1.170 +
   1.171 +    PR_Lock( traceLock );
   1.172 +    
   1.173 +    PR_INIT_CLIST( &qNameList );
   1.174 +
   1.175 +    lm = PR_NewLogModule("trace");
   1.176 +
   1.177 +    bufSize = DEFAULT_TRACE_BUFSIZE;
   1.178 +    NewTraceBuffer( bufSize );
   1.179 +
   1.180 +    /* Initialize logging controls */
   1.181 +    logLock = PR_NewLock();
   1.182 +    logCVar = PR_NewCondVar( logLock );
   1.183 +
   1.184 +    PR_Unlock( traceLock );
   1.185 +    return;    
   1.186 +} /* end _PR_InitializeTrace() */
   1.187 +
   1.188 +/*
   1.189 +** Create a Trace Handle
   1.190 +*/
   1.191 +PR_IMPLEMENT(PRTraceHandle)
   1.192 +	PR_CreateTrace( 
   1.193 +    	const char *qName,          /* QName for this trace handle */
   1.194 +	    const char *rName,          /* RName for this trace handle */
   1.195 +	    const char *description     /* description for this trace handle */
   1.196 +)
   1.197 +{
   1.198 +    QName   *qnp;
   1.199 +    RName   *rnp;
   1.200 +    PRBool  matchQname = PR_FALSE;
   1.201 +
   1.202 +    /* Self initialize, if necessary */
   1.203 +    if ( traceLock == NULL )
   1.204 +        _PR_InitializeTrace();
   1.205 +
   1.206 +    /* Validate input arguments */
   1.207 +    PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX );
   1.208 +    PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX );
   1.209 +    PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX );
   1.210 +
   1.211 +    PR_LOG( lm, PR_LOG_DEBUG,
   1.212 +            ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName));
   1.213 +
   1.214 +    /* Lock the Facility */
   1.215 +    PR_Lock( traceLock );
   1.216 +
   1.217 +    /* Do we already have a matching QName? */
   1.218 +    if (!PR_CLIST_IS_EMPTY( &qNameList ))
   1.219 +    {
   1.220 +        qnp = (QName *) PR_LIST_HEAD( &qNameList );
   1.221 +        do {
   1.222 +            if ( strcmp(qnp->name, qName) == 0)
   1.223 +            {
   1.224 +                matchQname = PR_TRUE;
   1.225 +                break;
   1.226 +            }
   1.227 +            qnp = (QName *)PR_NEXT_LINK( &qnp->link );
   1.228 +        } while( qnp != (QName *)&qNameList );
   1.229 +    }
   1.230 +    /*
   1.231 +    ** If we did not find a matching QName,
   1.232 +    **    allocate one and initialize it.
   1.233 +    **    link it onto the qNameList.
   1.234 +    **
   1.235 +    */
   1.236 +    if ( matchQname != PR_TRUE )
   1.237 +    {
   1.238 +        qnp = PR_NEWZAP( QName );
   1.239 +        PR_ASSERT( qnp != NULL );
   1.240 +        PR_INIT_CLIST( &qnp->link ); 
   1.241 +        PR_INIT_CLIST( &qnp->rNameList ); 
   1.242 +        strcpy( qnp->name, qName );
   1.243 +        PR_APPEND_LINK( &qnp->link, &qNameList ); 
   1.244 +    }
   1.245 +
   1.246 +    /* Do we already have a matching RName? */
   1.247 +    if (!PR_CLIST_IS_EMPTY( &qnp->rNameList ))
   1.248 +    {
   1.249 +        rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList );
   1.250 +        do {
   1.251 +            /*
   1.252 +            ** No duplicate RNames are allowed within a QName
   1.253 +            **
   1.254 +            */
   1.255 +            PR_ASSERT( strcmp(rnp->name, rName));
   1.256 +            rnp = (RName *)PR_NEXT_LINK( &rnp->link );
   1.257 +        } while( rnp != (RName *)&qnp->rNameList );
   1.258 +    }
   1.259 +
   1.260 +    /* Get a new RName structure; initialize its members */
   1.261 +    rnp = PR_NEWZAP( RName );
   1.262 +    PR_ASSERT( rnp != NULL );
   1.263 +    PR_INIT_CLIST( &rnp->link );
   1.264 +    strcpy( rnp->name, rName );
   1.265 +    strcpy( rnp->desc, description );
   1.266 +    rnp->lock = PR_NewLock();
   1.267 +    rnp->state = Running;
   1.268 +    if ( rnp->lock == NULL )
   1.269 +    {
   1.270 +        PR_ASSERT(0);
   1.271 +    }
   1.272 +
   1.273 +    PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */    
   1.274 +    rnp->qName = qnp;                       /* point the RName to the QName */
   1.275 +
   1.276 +    /* Unlock the Facility */
   1.277 +    PR_Unlock( traceLock );
   1.278 +    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t",
   1.279 +        qName, qnp, rName, rnp ));
   1.280 +
   1.281 +    return((PRTraceHandle)rnp);
   1.282 +} /* end  PR_CreateTrace() */
   1.283 +
   1.284 +/*
   1.285 +**
   1.286 +*/
   1.287 +PR_IMPLEMENT(void) 
   1.288 +	PR_DestroyTrace( 
   1.289 +		PRTraceHandle handle    /* Handle to be destroyed */
   1.290 +)
   1.291 +{
   1.292 +    RName   *rnp = (RName *)handle;
   1.293 +    QName   *qnp = rnp->qName;
   1.294 +
   1.295 +    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", 
   1.296 +        qnp->name, rnp->name));
   1.297 +
   1.298 +    /* Lock the Facility */
   1.299 +    PR_Lock( traceLock );
   1.300 +
   1.301 +    /*
   1.302 +    ** Remove RName from the list of RNames in QName
   1.303 +    ** and free RName
   1.304 +    */
   1.305 +    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", 
   1.306 +        rnp->name, rnp));
   1.307 +    PR_REMOVE_LINK( &rnp->link );
   1.308 +    PR_Free( rnp->lock );
   1.309 +    PR_DELETE( rnp );
   1.310 +
   1.311 +    /*
   1.312 +    ** If this is the last RName within QName
   1.313 +    **   remove QName from the qNameList and free it
   1.314 +    */
   1.315 +    if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) )
   1.316 +    {
   1.317 +        PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", 
   1.318 +            qnp->name, qnp));
   1.319 +        PR_REMOVE_LINK( &qnp->link );
   1.320 +        PR_DELETE( qnp );
   1.321 +    } 
   1.322 +
   1.323 +    /* Unlock the Facility */
   1.324 +    PR_Unlock( traceLock );
   1.325 +    return;
   1.326 +} /* end PR_DestroyTrace()  */
   1.327 +
   1.328 +/*
   1.329 +** Create a TraceEntry in the trace buffer
   1.330 +*/
   1.331 +PR_IMPLEMENT(void) 
   1.332 +	PR_Trace( 
   1.333 +    	PRTraceHandle handle,       /* use this trace handle */
   1.334 +	    PRUint32    userData0,      /* User supplied data word 0 */
   1.335 +	    PRUint32    userData1,      /* User supplied data word 1 */
   1.336 +	    PRUint32    userData2,      /* User supplied data word 2 */
   1.337 +	    PRUint32    userData3,      /* User supplied data word 3 */
   1.338 +	    PRUint32    userData4,      /* User supplied data word 4 */
   1.339 +	    PRUint32    userData5,      /* User supplied data word 5 */
   1.340 +	    PRUint32    userData6,      /* User supplied data word 6 */
   1.341 +	    PRUint32    userData7       /* User supplied data word 7 */
   1.342 +)
   1.343 +{
   1.344 +    PRTraceEntry   *tep;
   1.345 +    PRInt32         mark;
   1.346 +
   1.347 +    if ( (traceState == Suspended ) 
   1.348 +        || ( ((RName *)handle)->state == Suspended )) 
   1.349 +        return;
   1.350 +
   1.351 +    /*
   1.352 +    ** Get the next trace entry slot w/ minimum delay
   1.353 +    */
   1.354 +    PR_Lock( traceLock );
   1.355 +
   1.356 +    tep = &tBuf[next++]; 
   1.357 +    if ( next > last )
   1.358 +        next = 0;
   1.359 +    if ( fetchLostData == PR_FALSE && next == fetchLastSeen )
   1.360 +        fetchLostData = PR_TRUE;
   1.361 +    
   1.362 +    mark = next;
   1.363 +        
   1.364 +    PR_Unlock( traceLock );
   1.365 +
   1.366 +    /*
   1.367 +    ** We have a trace entry. Fill it in.
   1.368 +    */
   1.369 +    tep->thread = PR_GetCurrentThread();
   1.370 +    tep->handle = handle;
   1.371 +    tep->time   = PR_Now();
   1.372 +    tep->userData[0] = userData0;
   1.373 +    tep->userData[1] = userData1;
   1.374 +    tep->userData[2] = userData2;
   1.375 +    tep->userData[3] = userData3;
   1.376 +    tep->userData[4] = userData4;
   1.377 +    tep->userData[5] = userData5;
   1.378 +    tep->userData[6] = userData6;
   1.379 +    tep->userData[7] = userData7;
   1.380 +
   1.381 +    /* When buffer segment is full, signal trace log thread to run */
   1.382 +    if (( mark % logEntriesPerSegment) == 0 )
   1.383 +    {
   1.384 +        PR_Lock( logLock );
   1.385 +        logCount++;
   1.386 +        PR_NotifyCondVar( logCVar );
   1.387 +        PR_Unlock( logLock );
   1.388 +        /*
   1.389 +        ** Gh0D! This is awful!
   1.390 +        ** Anyway, to minimize lost trace data segments,
   1.391 +        ** I inserted the PR_Sleep(0) to cause a context switch
   1.392 +        ** so that the log thread could run.
   1.393 +        ** I know, it perturbs the universe and may cause
   1.394 +        ** funny things to happen in the optimized builds.
   1.395 +        ** Take it out, lose data; leave it in risk Heisenberg.
   1.396 +        */
   1.397 +        /* PR_Sleep(0); */
   1.398 +    }
   1.399 +
   1.400 +    return;
   1.401 +} /* end PR_Trace() */
   1.402 +
   1.403 +/*
   1.404 +**
   1.405 +*/
   1.406 +PR_IMPLEMENT(void) 
   1.407 +	PR_SetTraceOption( 
   1.408 +	    PRTraceOption command,  /* One of the enumerated values */
   1.409 +	    void *value             /* command value or NULL */
   1.410 +)
   1.411 +{
   1.412 +    RName * rnp;
   1.413 +
   1.414 +    switch ( command )
   1.415 +    {
   1.416 +        case PRTraceBufSize :
   1.417 +            PR_Lock( traceLock );
   1.418 +            PR_Free( tBuf );
   1.419 +            bufSize = *(PRInt32 *)value;
   1.420 +            NewTraceBuffer( bufSize );
   1.421 +            PR_Unlock( traceLock );
   1.422 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.423 +                ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize));
   1.424 +            break;
   1.425 +        
   1.426 +        case PRTraceEnable :
   1.427 +            rnp = *(RName **)value;
   1.428 +            rnp->state = Running;
   1.429 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.430 +                ("PRSetTraceOption: PRTraceEnable: %p", rnp));
   1.431 +            break;
   1.432 +        
   1.433 +        case PRTraceDisable :
   1.434 +            rnp = *(RName **)value;
   1.435 +            rnp->state = Suspended;
   1.436 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.437 +                ("PRSetTraceOption: PRTraceDisable: %p", rnp));
   1.438 +            break;
   1.439 +        
   1.440 +        case PRTraceSuspend :
   1.441 +            traceState = Suspended;
   1.442 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.443 +                ("PRSetTraceOption: PRTraceSuspend"));
   1.444 +            break;
   1.445 +        
   1.446 +        case PRTraceResume :
   1.447 +            traceState = Running;
   1.448 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.449 +                ("PRSetTraceOption: PRTraceResume"));
   1.450 +            break;
   1.451 +        
   1.452 +        case PRTraceSuspendRecording :
   1.453 +            PR_Lock( logLock );
   1.454 +            logOrder = LogSuspend;
   1.455 +            PR_NotifyCondVar( logCVar );
   1.456 +            PR_Unlock( logLock );
   1.457 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.458 +                ("PRSetTraceOption: PRTraceSuspendRecording"));
   1.459 +            break;
   1.460 +        
   1.461 +        case PRTraceResumeRecording :
   1.462 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.463 +                ("PRSetTraceOption: PRTraceResumeRecording"));
   1.464 +            if ( logState != LogSuspend )
   1.465 +                break;
   1.466 +            PR_Lock( logLock );
   1.467 +            logOrder = LogResume;
   1.468 +            PR_NotifyCondVar( logCVar );
   1.469 +            PR_Unlock( logLock );
   1.470 +            break;
   1.471 +        
   1.472 +        case PRTraceStopRecording :
   1.473 +            PR_Lock( logLock );
   1.474 +            logOrder = LogStop;
   1.475 +            PR_NotifyCondVar( logCVar );
   1.476 +            PR_Unlock( logLock );
   1.477 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.478 +                ("PRSetTraceOption: PRTraceStopRecording"));
   1.479 +            break;
   1.480 +
   1.481 +        case PRTraceLockHandles :
   1.482 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.483 +                ("PRSetTraceOption: PRTraceLockTraceHandles"));
   1.484 +            PR_Lock( traceLock );
   1.485 +            break;
   1.486 +        
   1.487 +        case PRTraceUnLockHandles :
   1.488 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.489 +                ("PRSetTraceOption: PRTraceUnLockHandles"));
   1.490 +            PR_Unlock( traceLock );
   1.491 +            break;
   1.492 +
   1.493 +        default:
   1.494 +            PR_LOG( lm, PR_LOG_ERROR,
   1.495 +                ("PRSetTraceOption: Invalid command %ld", command ));
   1.496 +            PR_ASSERT( 0 );
   1.497 +            break;
   1.498 +    } /* end switch() */
   1.499 +    return;
   1.500 +} /* end  PR_SetTraceOption() */
   1.501 +
   1.502 +/*
   1.503 +**
   1.504 +*/
   1.505 +PR_IMPLEMENT(void) 
   1.506 +	PR_GetTraceOption( 
   1.507 +    	PRTraceOption command,  /* One of the enumerated values */
   1.508 +	    void *value             /* command value or NULL */
   1.509 +)
   1.510 +{
   1.511 +    switch ( command )
   1.512 +    {
   1.513 +        case PRTraceBufSize :
   1.514 +            *((PRInt32 *)value) = bufSize;
   1.515 +            PR_LOG( lm, PR_LOG_DEBUG,
   1.516 +                ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize ));
   1.517 +            break;
   1.518 +        
   1.519 +        default:
   1.520 +            PR_LOG( lm, PR_LOG_ERROR,
   1.521 +                ("PRGetTraceOption: Invalid command %ld", command ));
   1.522 +            PR_ASSERT( 0 );
   1.523 +            break;
   1.524 +    } /* end switch() */
   1.525 +    return;
   1.526 +} /* end PR_GetTraceOption() */
   1.527 +
   1.528 +/*
   1.529 +**
   1.530 +*/
   1.531 +PR_IMPLEMENT(PRTraceHandle) 
   1.532 +	PR_GetTraceHandleFromName( 
   1.533 +    	const char *qName,      /* QName search argument */
   1.534 +        const char *rName       /* RName search argument */
   1.535 +)
   1.536 +{
   1.537 +    const char    *qn, *rn, *desc;
   1.538 +    PRTraceHandle     qh, rh = NULL;
   1.539 +    RName   *rnp = NULL;
   1.540 +
   1.541 +    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t"
   1.542 +        "QName: %s, RName: %s", qName, rName ));
   1.543 +
   1.544 +    qh = PR_FindNextTraceQname( NULL );
   1.545 +    while (qh != NULL)
   1.546 +    {
   1.547 +        rh = PR_FindNextTraceRname( NULL, qh );
   1.548 +        while ( rh != NULL )
   1.549 +        {
   1.550 +            PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc );
   1.551 +            if ( (strcmp( qName, qn ) == 0)
   1.552 +                && (strcmp( rName, rn ) == 0 ))
   1.553 +            {
   1.554 +                rnp = (RName *)rh;
   1.555 +                goto foundIt;
   1.556 +            }
   1.557 +            rh = PR_FindNextTraceRname( rh, qh );
   1.558 +        }
   1.559 +        qh = PR_FindNextTraceQname( NULL );
   1.560 +    }
   1.561 +
   1.562 +foundIt:
   1.563 +    PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
   1.564 +    return(rh);
   1.565 +} /* end PR_GetTraceHandleFromName() */
   1.566 +
   1.567 +/*
   1.568 +**
   1.569 +*/
   1.570 +PR_IMPLEMENT(void) 
   1.571 +	PR_GetTraceNameFromHandle( 
   1.572 +    	PRTraceHandle handle,       /* handle as search argument */
   1.573 +	    const char **qName,         /* pointer to associated QName */
   1.574 +	    const char **rName,         /* pointer to associated RName */
   1.575 +    	const char **description    /* pointer to associated description */
   1.576 +)
   1.577 +{
   1.578 +    RName   *rnp = (RName *)handle;
   1.579 +    QName   *qnp = rnp->qName;
   1.580 +
   1.581 +    *qName = qnp->name;
   1.582 +    *rName = rnp->name;
   1.583 +    *description = rnp->desc;
   1.584 +
   1.585 +    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetConterNameFromHandle: "
   1.586 +        "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", 
   1.587 +        qnp, rnp, qnp->name, rnp->name, rnp->desc ));
   1.588 +
   1.589 +    return;
   1.590 +} /* end PR_GetTraceNameFromHandle() */
   1.591 +
   1.592 +/*
   1.593 +**
   1.594 +*/
   1.595 +PR_IMPLEMENT(PRTraceHandle) 
   1.596 +	PR_FindNextTraceQname( 
   1.597 +        PRTraceHandle handle
   1.598 +)
   1.599 +{
   1.600 +    QName *qnp = (QName *)handle;
   1.601 +
   1.602 +    if ( PR_CLIST_IS_EMPTY( &qNameList ))
   1.603 +            qnp = NULL;
   1.604 +    else if ( qnp == NULL )
   1.605 +        qnp = (QName *)PR_LIST_HEAD( &qNameList );
   1.606 +    else if ( PR_NEXT_LINK( &qnp->link ) ==  &qNameList )
   1.607 +        qnp = NULL;
   1.608 +    else  
   1.609 +        qnp = (QName *)PR_NEXT_LINK( &qnp->link );
   1.610 +
   1.611 +    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p", 
   1.612 +        handle, qnp ));
   1.613 +
   1.614 +    return((PRTraceHandle)qnp);
   1.615 +} /* end PR_FindNextTraceQname() */
   1.616 +
   1.617 +/*
   1.618 +**
   1.619 +*/
   1.620 +PR_IMPLEMENT(PRTraceHandle) 
   1.621 +	PR_FindNextTraceRname( 
   1.622 +        PRTraceHandle rhandle,
   1.623 +        PRTraceHandle qhandle
   1.624 +)
   1.625 +{
   1.626 +    RName *rnp = (RName *)rhandle;
   1.627 +    QName *qnp = (QName *)qhandle;
   1.628 +
   1.629 +
   1.630 +    if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ))
   1.631 +        rnp = NULL;
   1.632 +    else if ( rnp == NULL )
   1.633 +        rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
   1.634 +    else if ( PR_NEXT_LINK( &rnp->link ) ==  &qnp->rNameList )
   1.635 +        rnp = NULL;
   1.636 +    else
   1.637 +        rnp = (RName *)PR_NEXT_LINK( &rnp->link );
   1.638 +
   1.639 +    PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 
   1.640 +        rhandle, qhandle, rnp ));
   1.641 +
   1.642 +    return((PRTraceHandle)rnp);
   1.643 +} /* end PR_FindNextTraceRname() */
   1.644 +    
   1.645 +/*
   1.646 +**
   1.647 +*/
   1.648 +static PRFileDesc * InitializeRecording( void )
   1.649 +{
   1.650 +    char    *logFileName;
   1.651 +    PRFileDesc  *logFile;
   1.652 +
   1.653 +    /* Self initialize, if necessary */
   1.654 +    if ( traceLock == NULL )
   1.655 +        _PR_InitializeTrace();
   1.656 +
   1.657 +    PR_LOG( lm, PR_LOG_DEBUG,
   1.658 +        ("PR_RecordTraceEntries: begins"));
   1.659 +
   1.660 +    logLostData = 0; /* reset at entry */
   1.661 +    logState = LogReset;
   1.662 +
   1.663 +#ifdef XP_UNIX
   1.664 +    if ((getuid() != geteuid()) || (getgid() != getegid())) {
   1.665 +        return NULL;
   1.666 +    }
   1.667 +#endif /* XP_UNIX */
   1.668 +
   1.669 +    /* Get the filename for the logfile from the environment */
   1.670 +    logFileName = PR_GetEnv( "NSPR_TRACE_LOG" );
   1.671 +    if ( logFileName == NULL )
   1.672 +    {
   1.673 +        PR_LOG( lm, PR_LOG_ERROR,
   1.674 +            ("RecordTraceEntries: Environment variable not defined. Exiting"));
   1.675 +        return NULL;
   1.676 +    }
   1.677 +    
   1.678 +    /* Open the logfile */
   1.679 +    logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 );
   1.680 +    if ( logFile == NULL )
   1.681 +    {
   1.682 +        PR_LOG( lm, PR_LOG_ERROR,
   1.683 +            ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld", 
   1.684 +		logFileName, PR_GetOSError()));
   1.685 +        return NULL;
   1.686 +    }
   1.687 +    return logFile;
   1.688 +} /* end InitializeRecording() */
   1.689 +
   1.690 +/*
   1.691 +**
   1.692 +*/
   1.693 +static void ProcessOrders( void )
   1.694 +{
   1.695 +    switch ( logOrder )
   1.696 +    {
   1.697 +    case LogReset :
   1.698 +        logOrder = logState = localState;
   1.699 +        PR_LOG( lm, PR_LOG_DEBUG,
   1.700 +            ("RecordTraceEntries: LogReset"));
   1.701 +        break;
   1.702 +
   1.703 +    case LogSuspend :
   1.704 +        localState = logOrder = logState = LogSuspend;
   1.705 +        PR_LOG( lm, PR_LOG_DEBUG,
   1.706 +            ("RecordTraceEntries: LogSuspend"));
   1.707 +        break;
   1.708 +
   1.709 +    case LogResume :
   1.710 +        localState = logOrder = logState = LogActive;
   1.711 +        PR_LOG( lm, PR_LOG_DEBUG,
   1.712 +            ("RecordTraceEntries: LogResume"));
   1.713 +        break;
   1.714 +
   1.715 +    case LogStop :
   1.716 +        logOrder = logState = LogStop;
   1.717 +        PR_LOG( lm, PR_LOG_DEBUG,
   1.718 +            ("RecordTraceEntries: LogStop"));
   1.719 +        break;
   1.720 +
   1.721 +    default :
   1.722 +        PR_LOG( lm, PR_LOG_ERROR,
   1.723 +            ("RecordTraceEntries: Invalid logOrder: %ld", logOrder ));
   1.724 +        PR_ASSERT( 0 );
   1.725 +        break;
   1.726 +    } /* end switch() */
   1.727 +    return ;
   1.728 +} /* end ProcessOrders() */
   1.729 +
   1.730 +/*
   1.731 +**
   1.732 +*/
   1.733 +static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount )
   1.734 +{
   1.735 +    PRInt32 rc;
   1.736 +
   1.737 +
   1.738 +    PR_LOG( lm, PR_LOG_ERROR,
   1.739 +        ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount));
   1.740 +    rc = PR_Write( logFile, buf , amount );
   1.741 +    if ( rc == -1 )
   1.742 +        PR_LOG( lm, PR_LOG_ERROR,
   1.743 +            ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() ));
   1.744 +    else if ( rc != amount )
   1.745 +        PR_LOG( lm, PR_LOG_ERROR,
   1.746 +            ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount, rc));
   1.747 +    else 
   1.748 +        PR_LOG( lm, PR_LOG_DEBUG,
   1.749 +            ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount));
   1.750 +
   1.751 +    return;
   1.752 +} /* end WriteTraceSegment() */
   1.753 +
   1.754 +/*
   1.755 +**
   1.756 +*/
   1.757 +PR_IMPLEMENT(void)
   1.758 +	PR_RecordTraceEntries(
   1.759 +        void 
   1.760 +)
   1.761 +{
   1.762 +    PRFileDesc  *logFile;
   1.763 +    PRInt32     lostSegments;
   1.764 +    PRInt32     currentSegment = 0;
   1.765 +    void        *buf;
   1.766 +    PRBool      doWrite;
   1.767 +
   1.768 +    logFile = InitializeRecording();
   1.769 +    if ( logFile == NULL )
   1.770 +    {
   1.771 +        PR_LOG( lm, PR_LOG_DEBUG,
   1.772 +            ("PR_RecordTraceEntries: Failed to initialize"));
   1.773 +        return;
   1.774 +    }
   1.775 +
   1.776 +    /* Do this until told to stop */
   1.777 +    while ( logState != LogStop )
   1.778 +    {
   1.779 +
   1.780 +        PR_Lock( logLock );
   1.781 +
   1.782 +        while ( (logCount == 0) && ( logOrder == logState ) )
   1.783 +            PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT );
   1.784 +
   1.785 +        /* Handle state transitions */
   1.786 +        if ( logOrder != logState )
   1.787 +            ProcessOrders();
   1.788 +
   1.789 +        /* recalculate local controls */
   1.790 +        if ( logCount )
   1.791 +        {
   1.792 +            lostSegments = logCount - logSegments;
   1.793 +            if ( lostSegments > 0 )
   1.794 +            {
   1.795 +                logLostData += ( logCount - logSegments );
   1.796 +                logCount = (logCount % logSegments);
   1.797 +                currentSegment = logCount;
   1.798 +                PR_LOG( lm, PR_LOG_DEBUG,
   1.799 +                    ("PR_RecordTraceEntries: LostData segments: %ld", logLostData));
   1.800 +            }
   1.801 +            else
   1.802 +            {
   1.803 +                logCount--;
   1.804 +            }
   1.805 +
   1.806 +            buf = tBuf + ( logEntriesPerSegment * currentSegment );
   1.807 +            if (++currentSegment >= logSegments )
   1.808 +                currentSegment = 0;
   1.809 +            doWrite = PR_TRUE;
   1.810 +        }
   1.811 +        else
   1.812 +            doWrite = PR_FALSE;
   1.813 +
   1.814 +        PR_Unlock( logLock );
   1.815 +
   1.816 +        if ( doWrite == PR_TRUE )
   1.817 +        {
   1.818 +            if ( localState != LogSuspend )
   1.819 +                WriteTraceSegment( logFile, buf, logSegSize );
   1.820 +            else
   1.821 +                PR_LOG( lm, PR_LOG_DEBUG,
   1.822 +                    ("RecordTraceEntries: PR_Write(): is suspended" ));
   1.823 +        }
   1.824 +
   1.825 +    } /* end while(logState...) */
   1.826 +
   1.827 +    PR_Close( logFile );
   1.828 +    PR_LOG( lm, PR_LOG_DEBUG,
   1.829 +        ("RecordTraceEntries: exiting"));
   1.830 +    return;
   1.831 +} /* end  PR_RecordTraceEntries() */
   1.832 +
   1.833 +/*
   1.834 +**
   1.835 +*/
   1.836 +PR_IMPLEMENT(PRIntn)
   1.837 +    PR_GetTraceEntries(
   1.838 +        PRTraceEntry    *buffer,    /* where to write output */
   1.839 +        PRInt32         count,      /* number to get */
   1.840 +        PRInt32         *found      /* number you got */
   1.841 +)
   1.842 +{
   1.843 +    PRInt32 rc; 
   1.844 +    PRInt32 copied = 0;
   1.845 +    
   1.846 +    PR_Lock( traceLock );
   1.847 +    
   1.848 +    /*
   1.849 +    ** Depending on where the LastSeen and Next indices are,
   1.850 +    ** copy the trace buffer in one or two pieces. 
   1.851 +    */
   1.852 +    PR_LOG( lm, PR_LOG_ERROR,
   1.853 +        ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen));
   1.854 +
   1.855 +    if ( fetchLastSeen <= next )
   1.856 +    {
   1.857 +        while (( count-- > 0 ) && (fetchLastSeen < next ))
   1.858 +        {
   1.859 +            *(buffer + copied++) = *(tBuf + fetchLastSeen++);
   1.860 +        }
   1.861 +        PR_LOG( lm, PR_LOG_ERROR,
   1.862 +            ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
   1.863 +    }
   1.864 +    else /* copy in 2 parts */
   1.865 +    {
   1.866 +        while ( count-- > 0  && fetchLastSeen <= last )
   1.867 +        {
   1.868 +            *(buffer + copied++) = *(tBuf + fetchLastSeen++);
   1.869 +        }
   1.870 +        fetchLastSeen = 0;
   1.871 +
   1.872 +        PR_LOG( lm, PR_LOG_ERROR,
   1.873 +            ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
   1.874 +
   1.875 +        while ( count-- > 0  && fetchLastSeen < next )
   1.876 +        {
   1.877 +            *(buffer + copied++) = *(tBuf + fetchLastSeen++);
   1.878 +        }
   1.879 +        PR_LOG( lm, PR_LOG_ERROR,
   1.880 +            ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
   1.881 +    }
   1.882 +
   1.883 +    *found = copied;
   1.884 +    rc = ( fetchLostData == PR_TRUE )? 1 : 0;
   1.885 +    fetchLostData = PR_FALSE;
   1.886 +
   1.887 +    PR_Unlock( traceLock );
   1.888 +    return rc;
   1.889 +} /* end PR_GetTraceEntries() */
   1.890 +
   1.891 +/* end prtrace.c */

mercurial