Back to index

lightning-sunbird  0.9+nobinonly
nssilock.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  * nssilock.c - NSS lock instrumentation wrapper functions
00039  *
00040  * NOTE - These are not public interfaces
00041  *
00042  * Implementation Notes:
00043  * I've tried to make the instrumentation relatively non-intrusive.
00044  * To do this, I have used a single PR_LOG() call in each
00045  * instrumented function. There's room for improvement.
00046  *
00047  *
00048  */
00049 
00050 #include "prinit.h"
00051 #include "prerror.h"
00052 #include "prlock.h"
00053 #include "prmem.h"
00054 #include "prenv.h"
00055 #include "prcvar.h"
00056 #include "prio.h"
00057 
00058 #if defined(NEED_NSS_ILOCK)
00059 #include "prlog.h"
00060 #include "nssilock.h"
00061 
00062 /*
00063 ** Declare the instrumented PZLock 
00064 */
00065 struct pzlock_s {
00066     PRLock *lock;  /* the PZLock to be instrumented */
00067     PRIntervalTime time; /* timestamp when the lock was aquired */
00068     nssILockType ltype;
00069 };
00070 
00071 /*
00072 ** Declare the instrumented PZMonitor 
00073 */
00074 struct pzmonitor_s {
00075     PRMonitor *mon;   /* the PZMonitor to be instrumented */
00076     PRIntervalTime time; /* timestamp when the monitor was aquired */
00077     nssILockType ltype;
00078 };
00079 
00080 /*
00081 ** Declare the instrumented PZCondVar
00082 */
00083 struct pzcondvar_s  {
00084     PRCondVar   *cvar;  /* the PZCondVar to be instrumented */
00085     nssILockType ltype;
00086 };
00087 
00088 
00089 /*
00090 ** Define a CallOnce type to ensure serialized self-initialization
00091 */
00092 static PRCallOnceType coNssILock;     /* CallOnce type */
00093 static PRIntn  nssILockInitialized;   /* initialization done when 1 */
00094 static PRLogModuleInfo *nssILog;      /* Log instrumentation to this handle */
00095 
00096 
00097 #define NUM_TT_ENTRIES 6000000
00098 static PRInt32  traceIndex = -1;      /* index into trace table */
00099 static struct pzTrace_s *tt;          /* pointer to trace table */
00100 static PRInt32  ttBufSize = (NUM_TT_ENTRIES * sizeof(struct pzTrace_s ));
00101 static PRCondVar *ttCVar;
00102 static PRLock    *ttLock;
00103 static PRFileDesc *ttfd;              /* trace table file */
00104 
00105 /*
00106 ** Vtrace() -- Trace events, write events to external media
00107 **
00108 ** Vtrace() records traced events in an in-memory trace table
00109 ** when the trace table fills, Vtrace writes the entire table
00110 ** to a file.
00111 **
00112 ** data can be lost!
00113 **
00114 */
00115 static void Vtrace(
00116     nssILockOp      op,
00117     nssILockType    ltype,
00118     PRIntervalTime  callTime,
00119     PRIntervalTime  heldTime,
00120     void            *lock,
00121     PRIntn          line,
00122     char            *file
00123 )  {
00124     PRInt32 idx;
00125     struct pzTrace_s *tp;
00126 
00127 RetryTrace:
00128     idx = PR_AtomicIncrement( &traceIndex );
00129     while( NUM_TT_ENTRIES <= idx || op == FlushTT ) {
00130         if( NUM_TT_ENTRIES == idx  || op == FlushTT )  {
00131             int writeSize = idx * sizeof(struct pzTrace_s);
00132             PR_Lock(ttLock);
00133             PR_Write( ttfd, tt, writeSize );
00134             traceIndex = -1;
00135             PR_NotifyAllCondVar( ttCVar );
00136             PR_Unlock(ttLock);
00137             goto RetryTrace;
00138         } else {
00139             PR_Lock(ttLock);
00140             while( NUM_TT_ENTRIES < idx )
00141                 PR_WaitCondVar(ttCVar, PR_INTERVAL_NO_WAIT);
00142             PR_Unlock(ttLock);
00143             goto RetryTrace;
00144         }
00145     } /* end while() */
00146 
00147     /* create the trace entry */
00148     tp = tt + idx;
00149     tp->threadID = PR_GetThreadID(PR_GetCurrentThread());
00150     tp->op = op;
00151     tp->ltype = ltype;
00152     tp->callTime = callTime;
00153     tp->heldTime = heldTime;
00154     tp->lock = lock;
00155     tp ->line = line;
00156     strcpy(tp->file, file );
00157     return;
00158 } /* --- end Vtrace() --- */
00159 
00160 /*
00161 ** pz_TraceFlush() -- Force trace table write to file
00162 **
00163 */
00164 extern void pz_TraceFlush( void )
00165 {
00166     Vtrace( FlushTT, nssILockSelfServ, 0, 0, NULL, 0, "" );
00167     return;
00168 } /* --- end pz_TraceFlush() --- */
00169 
00170 /*
00171 ** nssILockInit() -- Initialization for nssilock
00172 **
00173 ** This function is called from the CallOnce mechanism.
00174 */
00175 static PRStatus
00176     nssILockInit( void ) 
00177 {   
00178     int i;
00179     nssILockInitialized = 1;
00180 
00181     /* new log module */
00182     nssILog = PR_NewLogModule("nssilock");
00183     if ( NULL == nssILog )  {
00184         return(PR_FAILURE);
00185     }
00186 
00187     tt = PR_Calloc( NUM_TT_ENTRIES, sizeof(struct pzTrace_s));
00188     if (NULL == tt ) {
00189         fprintf(stderr, "nssilock: can't allocate trace table\n");
00190         exit(1);
00191     }
00192 
00193     ttfd = PR_Open( "xxxTTLog", PR_CREATE_FILE | PR_WRONLY, 0666 );
00194     if ( NULL == ttfd )  {
00195         fprintf( stderr, "Oh Drat! Can't open 'xxxTTLog'\n");
00196         exit(1);
00197     }
00198 
00199     ttLock = PR_NewLock();
00200     ttCVar = PR_NewCondVar(ttLock);
00201 
00202     return(PR_SUCCESS);
00203 } /* --- end nssILockInit() --- */
00204 
00205 extern PZLock * pz_NewLock( 
00206     nssILockType ltype,
00207     char *file,  
00208     PRIntn line )
00209 {
00210     PRStatus rc;
00211     PZLock  *lock;
00212     
00213     /* Self Initialize the nssILock feature */
00214     if (!nssILockInitialized)  {
00215         rc = PR_CallOnce( &coNssILock, nssILockInit );
00216         if ( PR_FAILURE == rc ) {
00217             PR_SetError( PR_UNKNOWN_ERROR, 0 );
00218             return( NULL );
00219         }
00220     }
00221 
00222     lock = PR_NEWZAP( PZLock );
00223     if ( NULL != lock )  {
00224         lock->lock = PR_NewLock();
00225         if ( NULL == lock->lock )  {
00226             PR_DELETE( lock );
00227             lock = NULL;
00228         }
00229     }
00230     lock->ltype = ltype;
00231 
00232     Vtrace( NewLock, ltype, 0, 0, lock, line, file );
00233     return(lock);
00234 } /* --- end pz_NewLock() --- */
00235 
00236 extern void
00237     pz_Lock(
00238         PZLock *lock,
00239         char *file,
00240         PRIntn line
00241     )
00242 {            
00243     PRIntervalTime callTime;
00244 
00245     callTime = PR_IntervalNow();
00246     PR_Lock( lock->lock );
00247     lock->time = PR_IntervalNow();
00248     callTime = lock->time - callTime;
00249 
00250     Vtrace( Lock, lock->ltype, callTime, 0, lock, line, file );
00251     return;
00252 } /* --- end  pz_Lock() --- */
00253 
00254 extern PRStatus
00255     pz_Unlock(
00256         PZLock *lock,
00257         char *file,
00258         PRIntn line
00259     ) 
00260 {
00261     PRStatus rc;
00262     PRIntervalTime callTime, now, heldTime;
00263 
00264     callTime = PR_IntervalNow();
00265     rc = PR_Unlock( lock->lock );
00266     now = PR_IntervalNow(); 
00267     callTime = now - callTime;
00268     heldTime = now - lock->time;
00269     Vtrace( Unlock, lock->ltype, callTime, heldTime, lock, line, file );
00270     return( rc );
00271 } /* --- end  pz_Unlock() --- */
00272 
00273 extern void
00274     pz_DestroyLock(
00275         PZLock *lock,
00276         char *file,
00277         PRIntn line
00278     )
00279 {
00280     Vtrace( DestroyLock, lock->ltype, 0, 0, lock, line, file );
00281     PR_DestroyLock( lock->lock );
00282     PR_DELETE( lock );
00283     return;
00284 } /* --- end  pz_DestroyLock() --- */
00285 
00286 
00287 
00288 extern PZCondVar *
00289     pz_NewCondVar(
00290         PZLock *lock,
00291         char *file,
00292         PRIntn line
00293     )
00294 {
00295     PZCondVar *cvar;
00296 
00297     cvar = PR_NEWZAP( PZCondVar );
00298     if ( NULL == cvar ) return(NULL);
00299    
00300     cvar->ltype = lock->ltype; 
00301     cvar->cvar = PR_NewCondVar( lock->lock );
00302     if ( NULL == cvar->cvar )  {
00303         PR_DELETE( cvar );
00304     }
00305     Vtrace( NewCondVar, cvar->ltype, 0, 0, cvar, line, file );
00306     return( cvar );
00307 } /* --- end  pz_NewCondVar() --- */
00308 
00309 extern void
00310     pz_DestroyCondVar(
00311         PZCondVar *cvar,
00312         char *file,
00313         PRIntn line
00314     )
00315 {
00316     Vtrace( DestroyCondVar, cvar->ltype, 0, 0, cvar, line, file );
00317     PR_DestroyCondVar( cvar->cvar );
00318     PR_DELETE( cvar );
00319 } /* --- end  pz_DestroyCondVar() --- */
00320 
00321 extern PRStatus
00322     pz_WaitCondVar(
00323         PZCondVar *cvar,
00324         PRIntervalTime timeout,
00325         char *file,
00326         PRIntn line
00327     )
00328 {
00329     PRStatus    rc;
00330     PRIntervalTime callTime;
00331 
00332     callTime = PR_IntervalNow();
00333     rc = PR_WaitCondVar( cvar->cvar, timeout );
00334     callTime = PR_IntervalNow() - callTime;
00335     
00336     Vtrace( WaitCondVar, cvar->ltype, callTime, 0, cvar, line, file );
00337     return(rc);
00338 } /* --- end  pz_WaitCondVar() --- */
00339 
00340 extern PRStatus
00341     pz_NotifyCondVar(
00342         PZCondVar *cvar,
00343         char *file,
00344         PRIntn line
00345     )
00346 {
00347     PRStatus    rc;
00348     
00349     rc = PR_NotifyCondVar( cvar->cvar );
00350     
00351     Vtrace( NotifyCondVar, cvar->ltype, 0, 0, cvar, line, file );
00352     return(rc);
00353 } /* --- end  pz_NotifyCondVar() --- */
00354 
00355 extern PRStatus
00356     pz_NotifyAllCondVar(
00357         PZCondVar *cvar,
00358         char *file,
00359         PRIntn line
00360     )
00361 {
00362     PRStatus    rc;
00363     
00364     rc = PR_NotifyAllCondVar( cvar->cvar );
00365     
00366     Vtrace( NotifyAllCondVar, cvar->ltype, 0, 0, cvar, line, file );
00367     return(rc);
00368 } /* --- end  pz_NotifyAllCondVar() --- */
00369 
00370 extern PZMonitor *
00371     pz_NewMonitor( 
00372         nssILockType ltype,
00373         char *file,
00374         PRIntn line
00375     )
00376 {
00377     PRStatus rc;
00378     PZMonitor   *mon;
00379 
00380     /* Self Initialize the nssILock feature */
00381     if (!nssILockInitialized)  {
00382         rc = PR_CallOnce( &coNssILock, nssILockInit );
00383         if ( PR_FAILURE == rc ) {
00384             PR_SetError( PR_UNKNOWN_ERROR, 0 );
00385             return( NULL );
00386         }
00387     }
00388 
00389     mon = PR_NEWZAP( PZMonitor );
00390     if ( NULL != mon )  {
00391         mon->mon = PR_NewMonitor();
00392         if ( NULL == mon->mon )  {
00393             PR_DELETE( mon );
00394             return NULL;
00395         }
00396     }
00397     mon->ltype = ltype;
00398 
00399     Vtrace( NewMonitor, mon->ltype, 0, 0, mon, line, file );
00400     return(mon);
00401 } /* --- end  pz_NewMonitor() --- */
00402 
00403 extern void
00404     pz_DestroyMonitor(
00405         PZMonitor *mon,
00406         char *file,
00407         PRIntn line
00408     )
00409 {
00410     Vtrace( DestroyMonitor, mon->ltype, 0, 0, mon, line, file );
00411     PR_DestroyMonitor( mon->mon );
00412     PR_DELETE( mon );
00413     return;                
00414 } /* --- end  pz_DestroyMonitor() --- */
00415 
00416 extern void
00417     pz_EnterMonitor(
00418         PZMonitor *mon,
00419         char *file,
00420         PRIntn line
00421     )
00422 {
00423     PRIntervalTime callTime, now;
00424 
00425     callTime = PR_IntervalNow();
00426     PR_EnterMonitor( mon->mon );
00427     now = PR_IntervalNow();
00428     callTime = now - callTime;
00429     if ( PR_GetMonitorEntryCount(mon->mon) == 1 )  {
00430         mon->time = now;
00431     }
00432     Vtrace( EnterMonitor, mon->ltype, callTime, 0, mon, line, file );
00433     return;
00434 } /* --- end  pz_EnterMonitor() --- */
00435 
00436 extern PRStatus
00437     pz_ExitMonitor(
00438         PZMonitor *mon,
00439         char *file,
00440         PRIntn line
00441     )
00442 {
00443     PRStatus rc;
00444     PRIntervalTime callTime, now, heldTime;
00445     PRIntn  mec = PR_GetMonitorEntryCount( mon->mon );
00446    
00447     heldTime = (PRIntervalTime)-1; 
00448     callTime = PR_IntervalNow();
00449     rc = PR_ExitMonitor( mon->mon );
00450     now = PR_IntervalNow();
00451     callTime = now - callTime;
00452     if ( mec == 1 )
00453         heldTime = now - mon->time;
00454     Vtrace( ExitMonitor, mon->ltype, callTime, heldTime, mon, line, file );
00455     return( rc );
00456 } /* --- end  pz_ExitMonitor() --- */
00457 
00458 extern PRIntn
00459     pz_GetMonitorEntryCount(
00460         PZMonitor *mon,
00461         char *file,
00462         PRIntn line
00463     )
00464 {
00465     return( PR_GetMonitorEntryCount(mon->mon));
00466 } /* --- end pz_GetMonitorEntryCount() --- */
00467 
00468 
00469 extern PRStatus
00470     pz_Wait(
00471         PZMonitor *mon,
00472         PRIntervalTime ticks,
00473         char *file,
00474         PRIntn line
00475     )
00476 {
00477     PRStatus rc;
00478     PRIntervalTime callTime;
00479 
00480     callTime = PR_IntervalNow();
00481     rc = PR_Wait( mon->mon, ticks );
00482     callTime = PR_IntervalNow() - callTime;
00483     Vtrace( Wait, mon->ltype, callTime, 0, mon, line, file );
00484     return( rc );
00485 } /* --- end  pz_Wait() --- */
00486 
00487 extern PRStatus
00488     pz_Notify(
00489         PZMonitor *mon,
00490         char *file,
00491         PRIntn line
00492     )
00493 {
00494     PRStatus rc;
00495     PRIntervalTime callTime;
00496 
00497     callTime = PR_IntervalNow();
00498     rc = PR_Notify( mon->mon );
00499     callTime = PR_IntervalNow() - callTime;
00500     Vtrace( Notify, mon->ltype, callTime, 0, mon, line, file );
00501     return( rc );
00502 } /* --- end  pz_Notify() --- */
00503 
00504 extern PRStatus
00505     pz_NotifyAll(
00506         PZMonitor *mon,
00507         char *file,
00508         PRIntn line
00509     )
00510 {
00511     PRStatus rc;
00512     PRIntervalTime callTime;
00513 
00514     callTime = PR_IntervalNow();
00515     rc = PR_NotifyAll( mon->mon );
00516     callTime = PR_IntervalNow() - callTime;
00517     Vtrace( NotifyAll, mon->ltype, callTime, 0, mon, line, file );
00518     return( rc );
00519 } /* --- end  pz_NotifyAll() --- */
00520 
00521 #endif /* NEED_NSS_ILOCK */
00522 /* --- end nssilock.c --------------------------------- */