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->ltype = ltype;
00225         lock->lock = PR_NewLock();
00226         if ( NULL == lock->lock )  {
00227             PR_DELETE( lock );
00228             PORT_SetError(SEC_ERROR_NO_MEMORY);
00229         }
00230     } else {
00231             PORT_SetError(SEC_ERROR_NO_MEMORY);
00232     }
00233 
00234     Vtrace( NewLock, ltype, 0, 0, lock, line, file );
00235     return(lock);
00236 } /* --- end pz_NewLock() --- */
00237 
00238 extern void
00239     pz_Lock(
00240         PZLock *lock,
00241         char *file,
00242         PRIntn line
00243     )
00244 {            
00245     PRIntervalTime callTime;
00246 
00247     callTime = PR_IntervalNow();
00248     PR_Lock( lock->lock );
00249     lock->time = PR_IntervalNow();
00250     callTime = lock->time - callTime;
00251 
00252     Vtrace( Lock, lock->ltype, callTime, 0, lock, line, file );
00253     return;
00254 } /* --- end  pz_Lock() --- */
00255 
00256 extern PRStatus
00257     pz_Unlock(
00258         PZLock *lock,
00259         char *file,
00260         PRIntn line
00261     ) 
00262 {
00263     PRStatus rc;
00264     PRIntervalTime callTime, now, heldTime;
00265 
00266     callTime = PR_IntervalNow();
00267     rc = PR_Unlock( lock->lock );
00268     now = PR_IntervalNow(); 
00269     callTime = now - callTime;
00270     heldTime = now - lock->time;
00271     Vtrace( Unlock, lock->ltype, callTime, heldTime, lock, line, file );
00272     return( rc );
00273 } /* --- end  pz_Unlock() --- */
00274 
00275 extern void
00276     pz_DestroyLock(
00277         PZLock *lock,
00278         char *file,
00279         PRIntn line
00280     )
00281 {
00282     Vtrace( DestroyLock, lock->ltype, 0, 0, lock, line, file );
00283     PR_DestroyLock( lock->lock );
00284     PR_DELETE( lock );
00285     return;
00286 } /* --- end  pz_DestroyLock() --- */
00287 
00288 
00289 
00290 extern PZCondVar *
00291     pz_NewCondVar(
00292         PZLock *lock,
00293         char *file,
00294         PRIntn line
00295     )
00296 {
00297     PZCondVar *cvar;
00298 
00299     cvar = PR_NEWZAP( PZCondVar );
00300     if ( NULL == cvar ) {
00301         PORT_SetError(SEC_ERROR_NO_MEMORY);
00302     } else {
00303         cvar->ltype = lock->ltype; 
00304         cvar->cvar = PR_NewCondVar( lock->lock );
00305         if ( NULL == cvar->cvar )  {
00306             PR_DELETE( cvar );
00307             PORT_SetError(SEC_ERROR_NO_MEMORY);
00308         }
00309 
00310     }
00311     Vtrace( NewCondVar, lock->ltype, 0, 0, cvar, line, file );
00312     return( cvar );
00313 } /* --- end  pz_NewCondVar() --- */
00314 
00315 extern void
00316     pz_DestroyCondVar(
00317         PZCondVar *cvar,
00318         char *file,
00319         PRIntn line
00320     )
00321 {
00322     Vtrace( DestroyCondVar, cvar->ltype, 0, 0, cvar, line, file );
00323     PR_DestroyCondVar( cvar->cvar );
00324     PR_DELETE( cvar );
00325 } /* --- end  pz_DestroyCondVar() --- */
00326 
00327 extern PRStatus
00328     pz_WaitCondVar(
00329         PZCondVar *cvar,
00330         PRIntervalTime timeout,
00331         char *file,
00332         PRIntn line
00333     )
00334 {
00335     PRStatus    rc;
00336     PRIntervalTime callTime;
00337 
00338     callTime = PR_IntervalNow();
00339     rc = PR_WaitCondVar( cvar->cvar, timeout );
00340     callTime = PR_IntervalNow() - callTime;
00341     
00342     Vtrace( WaitCondVar, cvar->ltype, callTime, 0, cvar, line, file );
00343     return(rc);
00344 } /* --- end  pz_WaitCondVar() --- */
00345 
00346 extern PRStatus
00347     pz_NotifyCondVar(
00348         PZCondVar *cvar,
00349         char *file,
00350         PRIntn line
00351     )
00352 {
00353     PRStatus    rc;
00354     
00355     rc = PR_NotifyCondVar( cvar->cvar );
00356     
00357     Vtrace( NotifyCondVar, cvar->ltype, 0, 0, cvar, line, file );
00358     return(rc);
00359 } /* --- end  pz_NotifyCondVar() --- */
00360 
00361 extern PRStatus
00362     pz_NotifyAllCondVar(
00363         PZCondVar *cvar,
00364         char *file,
00365         PRIntn line
00366     )
00367 {
00368     PRStatus    rc;
00369     
00370     rc = PR_NotifyAllCondVar( cvar->cvar );
00371     
00372     Vtrace( NotifyAllCondVar, cvar->ltype, 0, 0, cvar, line, file );
00373     return(rc);
00374 } /* --- end  pz_NotifyAllCondVar() --- */
00375 
00376 extern PZMonitor *
00377     pz_NewMonitor( 
00378         nssILockType ltype,
00379         char *file,
00380         PRIntn line
00381     )
00382 {
00383     PRStatus rc;
00384     PZMonitor   *mon;
00385 
00386     /* Self Initialize the nssILock feature */
00387     if (!nssILockInitialized)  {
00388         rc = PR_CallOnce( &coNssILock, nssILockInit );
00389         if ( PR_FAILURE == rc ) {
00390             PR_SetError( PR_UNKNOWN_ERROR, 0 );
00391             return( NULL );
00392         }
00393     }
00394 
00395     mon = PR_NEWZAP( PZMonitor );
00396     if ( NULL != mon )  {
00397         mon->ltype = ltype;
00398         mon->mon = PR_NewMonitor();
00399         if ( NULL == mon->mon )  {
00400             PR_DELETE( mon );
00401             PORT_SetError(SEC_ERROR_NO_MEMORY);
00402         }
00403     } else {
00404         PORT_SetError(SEC_ERROR_NO_MEMORY);
00405     }
00406 
00407     Vtrace( NewMonitor, ltype, 0, 0, mon, line, file );
00408     return(mon);
00409 } /* --- end  pz_NewMonitor() --- */
00410 
00411 extern void
00412     pz_DestroyMonitor(
00413         PZMonitor *mon,
00414         char *file,
00415         PRIntn line
00416     )
00417 {
00418     Vtrace( DestroyMonitor, mon->ltype, 0, 0, mon, line, file );
00419     PR_DestroyMonitor( mon->mon );
00420     PR_DELETE( mon );
00421     return;                
00422 } /* --- end  pz_DestroyMonitor() --- */
00423 
00424 extern void
00425     pz_EnterMonitor(
00426         PZMonitor *mon,
00427         char *file,
00428         PRIntn line
00429     )
00430 {
00431     PRIntervalTime callTime, now;
00432 
00433     callTime = PR_IntervalNow();
00434     PR_EnterMonitor( mon->mon );
00435     now = PR_IntervalNow();
00436     callTime = now - callTime;
00437     if ( PR_GetMonitorEntryCount(mon->mon) == 1 )  {
00438         mon->time = now;
00439     }
00440     Vtrace( EnterMonitor, mon->ltype, callTime, 0, mon, line, file );
00441     return;
00442 } /* --- end  pz_EnterMonitor() --- */
00443 
00444 extern PRStatus
00445     pz_ExitMonitor(
00446         PZMonitor *mon,
00447         char *file,
00448         PRIntn line
00449     )
00450 {
00451     PRStatus rc;
00452     PRIntervalTime callTime, now, heldTime;
00453     PRIntn  mec = PR_GetMonitorEntryCount( mon->mon );
00454    
00455     heldTime = (PRIntervalTime)-1; 
00456     callTime = PR_IntervalNow();
00457     rc = PR_ExitMonitor( mon->mon );
00458     now = PR_IntervalNow();
00459     callTime = now - callTime;
00460     if ( mec == 1 )
00461         heldTime = now - mon->time;
00462     Vtrace( ExitMonitor, mon->ltype, callTime, heldTime, mon, line, file );
00463     return( rc );
00464 } /* --- end  pz_ExitMonitor() --- */
00465 
00466 extern PRIntn
00467     pz_GetMonitorEntryCount(
00468         PZMonitor *mon,
00469         char *file,
00470         PRIntn line
00471     )
00472 {
00473     return( PR_GetMonitorEntryCount(mon->mon));
00474 } /* --- end pz_GetMonitorEntryCount() --- */
00475 
00476 
00477 extern PRStatus
00478     pz_Wait(
00479         PZMonitor *mon,
00480         PRIntervalTime ticks,
00481         char *file,
00482         PRIntn line
00483     )
00484 {
00485     PRStatus rc;
00486     PRIntervalTime callTime;
00487 
00488     callTime = PR_IntervalNow();
00489     rc = PR_Wait( mon->mon, ticks );
00490     callTime = PR_IntervalNow() - callTime;
00491     Vtrace( Wait, mon->ltype, callTime, 0, mon, line, file );
00492     return( rc );
00493 } /* --- end  pz_Wait() --- */
00494 
00495 extern PRStatus
00496     pz_Notify(
00497         PZMonitor *mon,
00498         char *file,
00499         PRIntn line
00500     )
00501 {
00502     PRStatus rc;
00503     PRIntervalTime callTime;
00504 
00505     callTime = PR_IntervalNow();
00506     rc = PR_Notify( mon->mon );
00507     callTime = PR_IntervalNow() - callTime;
00508     Vtrace( Notify, mon->ltype, callTime, 0, mon, line, file );
00509     return( rc );
00510 } /* --- end  pz_Notify() --- */
00511 
00512 extern PRStatus
00513     pz_NotifyAll(
00514         PZMonitor *mon,
00515         char *file,
00516         PRIntn line
00517     )
00518 {
00519     PRStatus rc;
00520     PRIntervalTime callTime;
00521 
00522     callTime = PR_IntervalNow();
00523     rc = PR_NotifyAll( mon->mon );
00524     callTime = PR_IntervalNow() - callTime;
00525     Vtrace( NotifyAll, mon->ltype, callTime, 0, mon, line, file );
00526     return( rc );
00527 } /* --- end  pz_NotifyAll() --- */
00528 
00529 #endif /* NEED_NSS_ILOCK */
00530 /* --- end nssilock.c --------------------------------- */