Back to index

lightning-sunbird  0.9+nobinonly
prtrace.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 ** prtrace.c -- NSPR Trace Instrumentation
00040 **
00041 ** Implement the API defined in prtrace.h
00042 **
00043 **
00044 **
00045 */
00046 
00047 #include <string.h>
00048 #include "primpl.h"
00049 
00050 
00051 #define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 )
00052 #define DEFAULT_BUFFER_SEGMENTS    2
00053 
00054 /*
00055 ** Enumerate states in a RName structure
00056 */
00057 typedef enum TraceState
00058 {
00059     Running = 1,
00060     Suspended = 2
00061 } TraceState;
00062 
00063 /*
00064 ** Define QName structure
00065 */
00066 typedef struct QName
00067 {
00068     PRCList link;
00069     PRCList rNameList;
00070     char    name[PRTRACE_NAME_MAX+1];
00071 } QName;
00072 
00073 /*
00074 ** Define RName structure
00075 */
00076 typedef struct RName
00077 {
00078     PRCList link;
00079     PRLock  *lock;
00080     QName   *qName;
00081     TraceState state;
00082     char    name[PRTRACE_NAME_MAX+1];
00083     char    desc[PRTRACE_DESC_MAX+1];
00084 } RName;
00085 
00086 
00087 /*
00088 ** The Trace Facility database
00089 **
00090 */
00091 static PRLogModuleInfo *lm;
00092 
00093 static PRLock      *traceLock;      /* Facility Lock */
00094 static PRCList     qNameList;       /* anchor to all QName structures */
00095 static TraceState traceState = Running;
00096 
00097 /*
00098 ** in-memory trace buffer controls
00099 */
00100 static  PRTraceEntry    *tBuf;      /* pointer to buffer */
00101 static  PRInt32         bufSize;    /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */
00102 static  volatile PRInt32  next;     /* index to next PRTraceEntry */
00103 static  PRInt32         last;       /* index of highest numbered trace entry */
00104 
00105 /*
00106 ** Real-time buffer capture controls
00107 */
00108 static PRInt32 fetchLastSeen = 0;
00109 static PRBool  fetchLostData = PR_FALSE;
00110 
00111 /*
00112 ** Buffer write-to-file controls
00113 */
00114 static  PRLock      *logLock;               /* Sync lock */
00115 static  PRCondVar   *logCVar;               /* Sync Condidtion Variable */
00116 /*
00117 ** Inter-thread state communication.
00118 ** Controling thread writes to logOrder under protection of logCVar
00119 ** the logging thread reads logOrder and sets logState on Notify.
00120 ** 
00121 ** logSegments, logCount, logLostData must be read and written under
00122 ** protection of logLock, logCVar.
00123 ** 
00124 */
00125 static  enum LogState
00126 {
00127     LogNotRunning,  /* Initial state */
00128     LogReset,       /* Causes logger to re-calc controls */
00129     LogActive,      /* Logging in progress, set only by log thread */
00130     LogSuspend,     /* Suspend Logging */ 
00131     LogResume,      /* Resume Logging => LogActive */ 
00132     LogStop         /* Stop the log thread */
00133 }   logOrder, logState, localState;         /* controlling state variables */
00134 static  PRInt32     logSegments;            /* Number of buffer segments */
00135 static  PRInt32     logEntries;             /* number of Trace Entries in the buffer */
00136 static  PRInt32     logEntriesPerSegment;   /* number of PRTraceEntries per buffer segment */
00137 static  PRInt32     logSegSize;             /* size of buffer segment */
00138 static  PRInt32     logCount;               /* number of segments pending output */
00139 static  PRInt32     logLostData;            /* number of lost log buffer segments */
00140 
00141 /*
00142 ** end Trace Database
00143 **
00144 */
00145 
00146 /*
00147 ** _PR_InitializeTrace() -- Initialize the trace facility
00148 */
00149 static void NewTraceBuffer( PRInt32 size )
00150 {
00151     /*
00152     ** calculate the size of the buffer
00153     ** round down so that each segment has the same number of
00154     ** trace entries
00155     */
00156     logSegments = DEFAULT_BUFFER_SEGMENTS;
00157     logEntries = size / sizeof(PRTraceEntry);
00158     logEntriesPerSegment = logEntries / logSegments;
00159     logEntries = logSegments * logEntriesPerSegment;
00160     bufSize = logEntries * sizeof(PRTraceEntry);
00161     logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry);
00162     PR_ASSERT( bufSize != 0);
00163     PR_LOG( lm, PR_LOG_ERROR,
00164         ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld",
00165             logSegments, logEntries, logEntriesPerSegment, logSegSize ));
00166 
00167 
00168     tBuf = PR_Malloc( bufSize );
00169     if ( tBuf == NULL )
00170     {
00171         PR_LOG( lm, PR_LOG_ERROR,
00172             ("PRTrace: Failed to get trace buffer"));
00173         PR_ASSERT( 0 );
00174     } 
00175     else
00176     {
00177         PR_LOG( lm, PR_LOG_NOTICE,
00178             ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf));
00179     }
00180 
00181     next = 0;
00182     last = logEntries -1;
00183     logCount = 0;
00184     logLostData = PR_TRUE; /* not really on first call */
00185     logOrder = LogReset;
00186 
00187 } /* end NewTraceBuffer() */
00188 
00189 /*
00190 ** _PR_InitializeTrace() -- Initialize the trace facility
00191 */
00192 static void _PR_InitializeTrace( void )
00193 {
00194     /* The lock pointer better be null on this call */
00195     PR_ASSERT( traceLock == NULL );
00196 
00197     traceLock = PR_NewLock();
00198     PR_ASSERT( traceLock != NULL );
00199 
00200     PR_Lock( traceLock );
00201     
00202     PR_INIT_CLIST( &qNameList );
00203 
00204     lm = PR_NewLogModule("trace");
00205 
00206     bufSize = DEFAULT_TRACE_BUFSIZE;
00207     NewTraceBuffer( bufSize );
00208 
00209     /* Initialize logging controls */
00210     logLock = PR_NewLock();
00211     logCVar = PR_NewCondVar( logLock );
00212 
00213     PR_Unlock( traceLock );
00214     return;    
00215 } /* end _PR_InitializeTrace() */
00216 
00217 /*
00218 ** Create a Trace Handle
00219 */
00220 PR_IMPLEMENT(PRTraceHandle)
00221        PR_CreateTrace( 
00222        const char *qName,          /* QName for this trace handle */
00223            const char *rName,          /* RName for this trace handle */
00224            const char *description     /* description for this trace handle */
00225 )
00226 {
00227     QName   *qnp;
00228     RName   *rnp;
00229     PRBool  matchQname = PR_FALSE;
00230 
00231     /* Self initialize, if necessary */
00232     if ( traceLock == NULL )
00233         _PR_InitializeTrace();
00234 
00235     /* Validate input arguments */
00236     PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX );
00237     PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX );
00238     PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX );
00239 
00240     PR_LOG( lm, PR_LOG_DEBUG,
00241             ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName));
00242 
00243     /* Lock the Facility */
00244     PR_Lock( traceLock );
00245 
00246     /* Do we already have a matching QName? */
00247     if (!PR_CLIST_IS_EMPTY( &qNameList ))
00248     {
00249         qnp = (QName *) PR_LIST_HEAD( &qNameList );
00250         do {
00251             if ( strcmp(qnp->name, qName) == 0)
00252             {
00253                 matchQname = PR_TRUE;
00254                 break;
00255             }
00256             qnp = (QName *)PR_NEXT_LINK( &qnp->link );
00257         } while( qnp != (QName *)PR_LIST_HEAD( &qNameList ));
00258     }
00259     /*
00260     ** If we did not find a matching QName,
00261     **    allocate one and initialize it.
00262     **    link it onto the qNameList.
00263     **
00264     */
00265     if ( matchQname != PR_TRUE )
00266     {
00267         qnp = PR_NEWZAP( QName );
00268         PR_ASSERT( qnp != NULL );
00269         PR_INIT_CLIST( &qnp->link ); 
00270         PR_INIT_CLIST( &qnp->rNameList ); 
00271         strcpy( qnp->name, qName );
00272         PR_APPEND_LINK( &qnp->link, &qNameList ); 
00273     }
00274 
00275     /* Do we already have a matching RName? */
00276     if (!PR_CLIST_IS_EMPTY( &qnp->rNameList ))
00277     {
00278         rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList );
00279         do {
00280             /*
00281             ** No duplicate RNames are allowed within a QName
00282             **
00283             */
00284             PR_ASSERT( strcmp(rnp->name, rName));
00285             rnp = (RName *)PR_NEXT_LINK( &rnp->link );
00286         } while( rnp != (RName *)PR_LIST_HEAD( &qnp->rNameList ));
00287     }
00288 
00289     /* Get a new RName structure; initialize its members */
00290     rnp = PR_NEWZAP( RName );
00291     PR_ASSERT( rnp != NULL );
00292     PR_INIT_CLIST( &rnp->link );
00293     strcpy( rnp->name, rName );
00294     strcpy( rnp->desc, description );
00295     rnp->lock = PR_NewLock();
00296     rnp->state = Running;
00297     if ( rnp->lock == NULL )
00298     {
00299         PR_ASSERT(0);
00300     }
00301 
00302     PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */    
00303     rnp->qName = qnp;                       /* point the RName to the QName */
00304 
00305     /* Unlock the Facility */
00306     PR_Unlock( traceLock );
00307     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t",
00308         qName, qnp, rName, rnp ));
00309 
00310     return((PRTraceHandle)rnp);
00311 } /* end  PR_CreateTrace() */
00312 
00313 /*
00314 **
00315 */
00316 PR_IMPLEMENT(void) 
00317        PR_DestroyTrace( 
00318               PRTraceHandle handle    /* Handle to be destroyed */
00319 )
00320 {
00321     RName   *rnp = (RName *)handle;
00322     QName   *qnp = rnp->qName;
00323 
00324     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", 
00325         qnp->name, rnp->name));
00326 
00327     /* Lock the Facility */
00328     PR_Lock( traceLock );
00329 
00330     /*
00331     ** Remove RName from the list of RNames in QName
00332     ** and free RName
00333     */
00334     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", 
00335         rnp->name, rnp));
00336     PR_REMOVE_LINK( &rnp->link );
00337     PR_Free( rnp->lock );
00338     PR_DELETE( rnp );
00339 
00340     /*
00341     ** If this is the last RName within QName
00342     **   remove QName from the qNameList and free it
00343     */
00344     if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) )
00345     {
00346         PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", 
00347             qnp->name, qnp));
00348         PR_REMOVE_LINK( &qnp->link );
00349         PR_DELETE( qnp );
00350     } 
00351 
00352     /* Unlock the Facility */
00353     PR_Unlock( traceLock );
00354     return;
00355 } /* end PR_DestroyTrace()  */
00356 
00357 /*
00358 ** Create a TraceEntry in the trace buffer
00359 */
00360 PR_IMPLEMENT(void) 
00361        PR_Trace( 
00362        PRTraceHandle handle,       /* use this trace handle */
00363            PRUint32    userData0,      /* User supplied data word 0 */
00364            PRUint32    userData1,      /* User supplied data word 1 */
00365            PRUint32    userData2,      /* User supplied data word 2 */
00366            PRUint32    userData3,      /* User supplied data word 3 */
00367            PRUint32    userData4,      /* User supplied data word 4 */
00368            PRUint32    userData5,      /* User supplied data word 5 */
00369            PRUint32    userData6,      /* User supplied data word 6 */
00370            PRUint32    userData7       /* User supplied data word 7 */
00371 )
00372 {
00373     PRTraceEntry   *tep;
00374     PRInt32         mark;
00375 
00376     if ( (traceState == Suspended ) 
00377         || ( ((RName *)handle)->state == Suspended )) 
00378         return;
00379 
00380     /*
00381     ** Get the next trace entry slot w/ minimum delay
00382     */
00383     PR_Lock( traceLock );
00384 
00385     tep = &tBuf[next++]; 
00386     if ( next > last )
00387         next = 0;
00388     if ( fetchLostData == PR_FALSE && next == fetchLastSeen )
00389         fetchLostData = PR_TRUE;
00390     
00391     mark = next;
00392         
00393     PR_Unlock( traceLock );
00394 
00395     /*
00396     ** We have a trace entry. Fill it in.
00397     */
00398     tep->thread = PR_GetCurrentThread();
00399     tep->handle = handle;
00400     tep->time   = PR_Now();
00401     tep->userData[0] = userData0;
00402     tep->userData[1] = userData1;
00403     tep->userData[2] = userData2;
00404     tep->userData[3] = userData3;
00405     tep->userData[4] = userData4;
00406     tep->userData[5] = userData5;
00407     tep->userData[6] = userData6;
00408     tep->userData[7] = userData7;
00409 
00410     /* When buffer segment is full, signal trace log thread to run */
00411     if (( mark % logEntriesPerSegment) == 0 )
00412     {
00413         PR_Lock( logLock );
00414         logCount++;
00415         PR_NotifyCondVar( logCVar );
00416         PR_Unlock( logLock );
00417         /*
00418         ** Gh0D! This is awful!
00419         ** Anyway, to minimize lost trace data segments,
00420         ** I inserted the PR_Sleep(0) to cause a context switch
00421         ** so that the log thread could run.
00422         ** I know, it perturbs the universe and may cause
00423         ** funny things to happen in the optimized builds.
00424         ** Take it out, loose data; leave it in risk Heisenberg.
00425         */
00426         /* PR_Sleep(0); */
00427     }
00428 
00429     return;
00430 } /* end PR_Trace() */
00431 
00432 /*
00433 **
00434 */
00435 PR_IMPLEMENT(void) 
00436        PR_SetTraceOption( 
00437            PRTraceOption command,  /* One of the enumerated values */
00438            void *value             /* command value or NULL */
00439 )
00440 {
00441     RName * rnp;
00442 
00443     switch ( command )
00444     {
00445         case PRTraceBufSize :
00446             PR_Lock( traceLock );
00447             PR_Free( tBuf );
00448             bufSize = *(PRInt32 *)value;
00449             NewTraceBuffer( bufSize );
00450             PR_Unlock( traceLock );
00451             PR_LOG( lm, PR_LOG_DEBUG,
00452                 ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize));
00453             break;
00454         
00455         case PRTraceEnable :
00456             rnp = *(RName **)value;
00457             rnp->state = Running;
00458             PR_LOG( lm, PR_LOG_DEBUG,
00459                 ("PRSetTraceOption: PRTraceEnable: %p", rnp));
00460             break;
00461         
00462         case PRTraceDisable :
00463             rnp = *(RName **)value;
00464             rnp->state = Suspended;
00465             PR_LOG( lm, PR_LOG_DEBUG,
00466                 ("PRSetTraceOption: PRTraceDisable: %p", rnp));
00467             break;
00468         
00469         case PRTraceSuspend :
00470             traceState = Suspended;
00471             PR_LOG( lm, PR_LOG_DEBUG,
00472                 ("PRSetTraceOption: PRTraceSuspend"));
00473             break;
00474         
00475         case PRTraceResume :
00476             traceState = Running;
00477             PR_LOG( lm, PR_LOG_DEBUG,
00478                 ("PRSetTraceOption: PRTraceResume"));
00479             break;
00480         
00481         case PRTraceSuspendRecording :
00482             PR_Lock( logLock );
00483             logOrder = LogSuspend;
00484             PR_NotifyCondVar( logCVar );
00485             PR_Unlock( logLock );
00486             PR_LOG( lm, PR_LOG_DEBUG,
00487                 ("PRSetTraceOption: PRTraceSuspendRecording"));
00488             break;
00489         
00490         case PRTraceResumeRecording :
00491             PR_LOG( lm, PR_LOG_DEBUG,
00492                 ("PRSetTraceOption: PRTraceResumeRecording"));
00493             if ( logState != LogSuspend )
00494                 break;
00495             PR_Lock( logLock );
00496             logOrder = LogResume;
00497             PR_NotifyCondVar( logCVar );
00498             PR_Unlock( logLock );
00499             break;
00500         
00501         case PRTraceStopRecording :
00502             PR_Lock( logLock );
00503             logOrder = LogStop;
00504             PR_NotifyCondVar( logCVar );
00505             PR_Unlock( logLock );
00506             PR_LOG( lm, PR_LOG_DEBUG,
00507                 ("PRSetTraceOption: PRTraceStopRecording"));
00508             break;
00509 
00510         case PRTraceLockHandles :
00511             PR_LOG( lm, PR_LOG_DEBUG,
00512                 ("PRSetTraceOption: PRTraceLockTraceHandles"));
00513             PR_Lock( traceLock );
00514             break;
00515         
00516         case PRTraceUnLockHandles :
00517             PR_LOG( lm, PR_LOG_DEBUG,
00518                 ("PRSetTraceOption: PRTraceUnLockHandles"));
00519             PR_Lock( traceLock );
00520             break;
00521 
00522         default:
00523             PR_LOG( lm, PR_LOG_ERROR,
00524                 ("PRSetTraceOption: Invalid command %ld", command ));
00525             PR_ASSERT( 0 );
00526             break;
00527     } /* end switch() */
00528     return;
00529 } /* end  PR_SetTraceOption() */
00530 
00531 /*
00532 **
00533 */
00534 PR_IMPLEMENT(void) 
00535        PR_GetTraceOption( 
00536        PRTraceOption command,  /* One of the enumerated values */
00537            void *value             /* command value or NULL */
00538 )
00539 {
00540     switch ( command )
00541     {
00542         case PRTraceBufSize :
00543             *((PRInt32 *)value) = bufSize;
00544             PR_LOG( lm, PR_LOG_DEBUG,
00545                 ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize ));
00546             break;
00547         
00548         default:
00549             PR_LOG( lm, PR_LOG_ERROR,
00550                 ("PRGetTraceOption: Invalid command %ld", command ));
00551             PR_ASSERT( 0 );
00552             break;
00553     } /* end switch() */
00554     return;
00555 } /* end PR_GetTraceOption() */
00556 
00557 /*
00558 **
00559 */
00560 PR_IMPLEMENT(PRTraceHandle) 
00561        PR_GetTraceHandleFromName( 
00562        const char *qName,      /* QName search argument */
00563         const char *rName       /* RName search argument */
00564 )
00565 {
00566     const char    *qn, *rn, *desc;
00567     PRTraceHandle     qh, rh = NULL;
00568     RName   *rnp = NULL;
00569 
00570     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t"
00571         "QName: %s, RName: %s", qName, rName ));
00572 
00573     qh = PR_FindNextTraceQname( NULL );
00574     while (qh != NULL)
00575     {
00576         rh = PR_FindNextTraceRname( NULL, qh );
00577         while ( rh != NULL )
00578         {
00579             PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc );
00580             if ( (strcmp( qName, qn ) == 0)
00581                 && (strcmp( rName, rn ) == 0 ))
00582             {
00583                 rnp = (RName *)rh;
00584                 goto foundIt;
00585             }
00586             rh = PR_FindNextTraceRname( rh, qh );
00587         }
00588         qh = PR_FindNextTraceQname( NULL );
00589     }
00590 
00591 foundIt:
00592     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
00593     return(rh);
00594 } /* end PR_GetTraceHandleFromName() */
00595 
00596 /*
00597 **
00598 */
00599 PR_IMPLEMENT(void) 
00600        PR_GetTraceNameFromHandle( 
00601        PRTraceHandle handle,       /* handle as search argument */
00602            const char **qName,         /* pointer to associated QName */
00603            const char **rName,         /* pointer to associated RName */
00604        const char **description    /* pointer to associated description */
00605 )
00606 {
00607     RName   *rnp = (RName *)handle;
00608     QName   *qnp = rnp->qName;
00609 
00610     *qName = qnp->name;
00611     *rName = rnp->name;
00612     *description = rnp->desc;
00613 
00614     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetConterNameFromHandle: "
00615         "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", 
00616         qnp, rnp, qnp->name, rnp->name, rnp->desc ));
00617 
00618     return;
00619 } /* end PR_GetTraceNameFromHandle() */
00620 
00621 /*
00622 **
00623 */
00624 PR_IMPLEMENT(PRTraceHandle) 
00625        PR_FindNextTraceQname( 
00626         PRTraceHandle handle
00627 )
00628 {
00629     QName *qnp = (QName *)handle;
00630 
00631     if ( PR_CLIST_IS_EMPTY( &qNameList ))
00632             qnp = NULL;
00633     else if ( qnp == NULL )
00634         qnp = (QName *)PR_LIST_HEAD( &qNameList );
00635     else if ( PR_NEXT_LINK( &qnp->link ) ==  &qNameList )
00636         qnp = NULL;
00637     else  
00638         qnp = (QName *)PR_NEXT_LINK( &qnp->link );
00639 
00640     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p", 
00641         handle, qnp ));
00642 
00643     return((PRTraceHandle)qnp);
00644 } /* end PR_FindNextTraceQname() */
00645 
00646 /*
00647 **
00648 */
00649 PR_IMPLEMENT(PRTraceHandle) 
00650        PR_FindNextTraceRname( 
00651         PRTraceHandle rhandle,
00652         PRTraceHandle qhandle
00653 )
00654 {
00655     RName *rnp = (RName *)rhandle;
00656     QName *qnp = (QName *)qhandle;
00657 
00658 
00659     if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ))
00660         rnp = NULL;
00661     else if ( rnp == NULL )
00662         rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
00663     else if ( PR_NEXT_LINK( &rnp->link ) ==  &qnp->rNameList )
00664         rnp = NULL;
00665     else
00666         rnp = (RName *)PR_NEXT_LINK( &rnp->link );
00667 
00668     PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 
00669         rhandle, qhandle, rnp ));
00670 
00671     return((PRTraceHandle)rnp);
00672 } /* end PR_FindNextTraceRname() */
00673     
00674 /*
00675 **
00676 */
00677 static PRFileDesc * InitializeRecording( void )
00678 {
00679     char    *logFileName;
00680     PRFileDesc  *logFile;
00681 
00682     /* Self initialize, if necessary */
00683     if ( traceLock == NULL )
00684         _PR_InitializeTrace();
00685 
00686     PR_LOG( lm, PR_LOG_DEBUG,
00687         ("PR_RecordTraceEntries: begins"));
00688 
00689     logLostData = 0; /* reset at entry */
00690     logState = LogReset;
00691 
00692 #ifdef XP_UNIX
00693     if ((getuid() != geteuid()) || (getgid() != getegid())) {
00694         return NULL;
00695     }
00696 #endif /* XP_UNIX */
00697 
00698     /* Get the filename for the logfile from the environment */
00699     logFileName = PR_GetEnv( "NSPR_TRACE_LOG" );
00700     if ( logFileName == NULL )
00701     {
00702         PR_LOG( lm, PR_LOG_ERROR,
00703             ("RecordTraceEntries: Environment variable not defined. Exiting"));
00704         return NULL;
00705     }
00706     
00707     /* Open the logfile */
00708     logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 );
00709     if ( logFile == NULL )
00710     {
00711         PR_LOG( lm, PR_LOG_ERROR,
00712             ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld", 
00713               logFileName, PR_GetOSError()));
00714         return NULL;
00715     }
00716     return logFile;
00717 } /* end InitializeRecording() */
00718 
00719 /*
00720 **
00721 */
00722 static void ProcessOrders( void )
00723 {
00724     switch ( logOrder )
00725     {
00726     case LogReset :
00727         logOrder = logState = localState;
00728         PR_LOG( lm, PR_LOG_DEBUG,
00729             ("RecordTraceEntries: LogReset"));
00730         break;
00731 
00732     case LogSuspend :
00733         localState = logOrder = logState = LogSuspend;
00734         PR_LOG( lm, PR_LOG_DEBUG,
00735             ("RecordTraceEntries: LogSuspend"));
00736         break;
00737 
00738     case LogResume :
00739         localState = logOrder = logState = LogActive;
00740         PR_LOG( lm, PR_LOG_DEBUG,
00741             ("RecordTraceEntries: LogResume"));
00742         break;
00743 
00744     case LogStop :
00745         logOrder = logState = LogStop;
00746         PR_LOG( lm, PR_LOG_DEBUG,
00747             ("RecordTraceEntries: LogStop"));
00748         break;
00749 
00750     default :
00751         PR_LOG( lm, PR_LOG_ERROR,
00752             ("RecordTraceEntries: Invalid logOrder: %ld", logOrder ));
00753         PR_ASSERT( 0 );
00754         break;
00755     } /* end switch() */
00756     return ;
00757 } /* end ProcessOrders() */
00758 
00759 /*
00760 **
00761 */
00762 static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount )
00763 {
00764     PRInt32 rc;
00765 
00766 
00767     PR_LOG( lm, PR_LOG_ERROR,
00768         ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount));
00769     rc = PR_Write( logFile, buf , amount );
00770     if ( rc == -1 )
00771         PR_LOG( lm, PR_LOG_ERROR,
00772             ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() ));
00773     else if ( rc != amount )
00774         PR_LOG( lm, PR_LOG_ERROR,
00775             ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount, rc));
00776     else 
00777         PR_LOG( lm, PR_LOG_DEBUG,
00778             ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount));
00779 
00780     return;
00781 } /* end WriteTraceSegment() */
00782 
00783 /*
00784 **
00785 */
00786 PR_IMPLEMENT(void)
00787        PR_RecordTraceEntries(
00788         void 
00789 )
00790 {
00791     PRFileDesc  *logFile;
00792     PRInt32     lostSegments;
00793     PRInt32     currentSegment = 0;
00794     void        *buf;
00795     PRBool      doWrite;
00796 
00797     logFile = InitializeRecording();
00798     if ( logFile == NULL )
00799     {
00800         PR_LOG( lm, PR_LOG_DEBUG,
00801             ("PR_RecordTraceEntries: Failed to initialize"));
00802         return;
00803     }
00804 
00805     /* Do this until told to stop */
00806     while ( logState != LogStop )
00807     {
00808 
00809         PR_Lock( logLock );
00810 
00811         while ( (logCount == 0) && ( logOrder == logState ) )
00812             PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT );
00813 
00814         /* Handle state transitions */
00815         if ( logOrder != logState )
00816             ProcessOrders();
00817 
00818         /* recalculate local controls */
00819         if ( logCount )
00820         {
00821             lostSegments = logCount - logSegments;
00822             if ( lostSegments > 0 )
00823             {
00824                 logLostData += ( logCount - logSegments );
00825                 logCount = (logCount % logSegments);
00826                 currentSegment = logCount;
00827                 PR_LOG( lm, PR_LOG_DEBUG,
00828                     ("PR_RecordTraceEntries: LostData segments: %ld", logLostData));
00829             }
00830             else
00831             {
00832                 logCount--;
00833             }
00834 
00835             buf = tBuf + ( logEntriesPerSegment * currentSegment );
00836             if (++currentSegment >= logSegments )
00837                 currentSegment = 0;
00838             doWrite = PR_TRUE;
00839         }
00840         else
00841             doWrite = PR_FALSE;
00842 
00843         PR_Unlock( logLock );
00844 
00845         if ( doWrite == PR_TRUE )
00846         {
00847             if ( localState != LogSuspend )
00848                 WriteTraceSegment( logFile, buf, logSegSize );
00849             else
00850                 PR_LOG( lm, PR_LOG_DEBUG,
00851                     ("RecordTraceEntries: PR_Write(): is suspended" ));
00852         }
00853 
00854     } /* end while(logState...) */
00855 
00856     PR_Close( logFile );
00857     PR_LOG( lm, PR_LOG_DEBUG,
00858         ("RecordTraceEntries: exiting"));
00859     return;
00860 } /* end  PR_RecordTraceEntries() */
00861 
00862 /*
00863 **
00864 */
00865 PR_IMPLEMENT(PRIntn)
00866     PR_GetTraceEntries(
00867         PRTraceEntry    *buffer,    /* where to write output */
00868         PRInt32         count,      /* number to get */
00869         PRInt32         *found      /* number you got */
00870 )
00871 {
00872     PRInt32 rc; 
00873     PRInt32 copied = 0;
00874     
00875     PR_Lock( traceLock );
00876     
00877     /*
00878     ** Depending on where the LastSeen and Next indices are,
00879     ** copy the trace buffer in one or two pieces. 
00880     */
00881     PR_LOG( lm, PR_LOG_ERROR,
00882         ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen));
00883 
00884     if ( fetchLastSeen <= next )
00885     {
00886         while (( count-- > 0 ) && (fetchLastSeen < next ))
00887         {
00888             *(buffer + copied++) = *(tBuf + fetchLastSeen++);
00889         }
00890         PR_LOG( lm, PR_LOG_ERROR,
00891             ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
00892     }
00893     else /* copy in 2 parts */
00894     {
00895         while ( count-- > 0  && fetchLastSeen <= last )
00896         {
00897             *(buffer + copied++) = *(tBuf + fetchLastSeen++);
00898         }
00899         fetchLastSeen = 0;
00900 
00901         PR_LOG( lm, PR_LOG_ERROR,
00902             ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
00903 
00904         while ( count-- > 0  && fetchLastSeen < next )
00905         {
00906             *(buffer + copied++) = *(tBuf + fetchLastSeen++);
00907         }
00908         PR_LOG( lm, PR_LOG_ERROR,
00909             ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
00910     }
00911 
00912     *found = copied;
00913     rc = ( fetchLostData == PR_TRUE )? 1 : 0;
00914     fetchLostData = PR_FALSE;
00915 
00916     PR_Unlock( traceLock );
00917     return rc;
00918 } /* end PR_GetTraceEntries() */
00919 
00920 /* end prtrace.c */