Back to index

lightning-sunbird  0.9+nobinonly
prgcapi.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 #include <stdarg.h>
00039 #include <string.h>
00040 #include <stdio.h>
00041 #include "prenv.h"
00042 #include "prmem.h"
00043 #include "prmon.h"
00044 #include "prlog.h"
00045 #include "prthread.h"
00046 #if defined(XP_MAC)
00047 #include "pprthred.h"
00048 #else
00049 #include "private/pprthred.h"
00050 #endif
00051 #include "gcint.h"
00052 
00053 /*
00054 ** Generic GC implementation independent code for the NSPR GC
00055 */
00056 
00057 RootFinder *_pr_rootFinders;
00058 
00059 CollectorType *_pr_collectorTypes;
00060 
00061 /* GC State information */
00062 GCInfo _pr_gcData;
00063 
00064 GCBeginGCHook *_pr_beginGCHook;
00065 void *_pr_beginGCHookArg;
00066 GCBeginGCHook *_pr_endGCHook;
00067 void *_pr_endGCHookArg;
00068 
00069 GCBeginFinalizeHook *_pr_beginFinalizeHook;
00070 void *_pr_beginFinalizeHookArg;
00071 GCBeginFinalizeHook *_pr_endFinalizeHook;
00072 void *_pr_endFinalizeHookArg;
00073 
00074 FILE *_pr_dump_file;
00075 int _pr_do_a_dump;
00076 GCLockHook *_pr_GCLockHook;
00077 
00078 extern PRLogModuleInfo *_pr_msgc_lm;
00079 
00080 /************************************************************************/
00081 
00082 static PRStatus PR_CALLBACK
00083 pr_ScanOneThread(PRThread* t, void** addr, PRUword count, void* closure)
00084 {
00085 #if defined(XP_MAC)
00086 #pragma unused (t, closure)
00087 #endif
00088 
00089     _pr_gcData.processRootBlock(addr, count);
00090     return PR_SUCCESS;
00091 }
00092 
00093 /*
00094 ** Scan all of the threads C stack's and registers, looking for "root"
00095 ** pointers into the GC heap. These are the objects that the GC cannot
00096 ** move and are considered "live" by the GC. Caller has stopped all of
00097 ** the threads from running.
00098 */
00099 static void PR_CALLBACK ScanThreads(void *arg)
00100 {
00101     PR_ScanStackPointers(pr_ScanOneThread, arg);
00102 }
00103 
00104 /************************************************************************/
00105 
00106 PR_IMPLEMENT(GCInfo *) PR_GetGCInfo(void)
00107 {
00108     return &_pr_gcData;
00109 }
00110 
00111 
00112 PR_IMPLEMENT(PRInt32) PR_RegisterType(GCType *t)
00113 {
00114     CollectorType *ct, *ect;
00115     int rv = -1;
00116 
00117     LOCK_GC();
00118     ct = &_pr_collectorTypes[0];
00119     ect = &_pr_collectorTypes[FREE_MEMORY_TYPEIX];
00120     for (; ct < ect; ct++) {
00121        if (ct->flags == 0) {
00122            ct->gctype = *t;
00123            ct->flags = _GC_TYPE_BUSY;
00124            if (0 != ct->gctype.finalize) {
00125               ct->flags |= _GC_TYPE_FINAL;
00126            }
00127            if (0 != ct->gctype.getWeakLinkOffset) {
00128               ct->flags |= _GC_TYPE_WEAK;
00129            }
00130            rv = ct - &_pr_collectorTypes[0];
00131            break;
00132        }
00133     }
00134     UNLOCK_GC();
00135     return rv;
00136 }
00137 
00138 PR_IMPLEMENT(PRStatus) PR_RegisterRootFinder(
00139     GCRootFinder f, char *name, void *arg)
00140 {
00141     RootFinder *rf = PR_NEWZAP(RootFinder);
00142     if (rf) {
00143            rf->func = f;
00144            rf->name = name;
00145            rf->arg = arg;
00146 
00147            LOCK_GC();
00148            rf->next = _pr_rootFinders;
00149            _pr_rootFinders = rf;
00150            UNLOCK_GC();
00151            return PR_SUCCESS;
00152     }
00153     return PR_FAILURE;
00154 }
00155 
00156 
00157 PR_IMPLEMENT(int) PR_RegisterGCLockHook(GCLockHookFunc* f, void *arg)
00158 {
00159 
00160     GCLockHook *rf = 0;
00161 
00162     rf = (GCLockHook*) calloc(1, sizeof(GCLockHook));
00163     if (rf) {
00164        rf->func = f;
00165        rf->arg = arg;
00166 
00167        LOCK_GC();
00168         /* first dummy node */
00169         if (! _pr_GCLockHook) {
00170           _pr_GCLockHook = (GCLockHook*) calloc(1, sizeof(GCLockHook));
00171           _pr_GCLockHook->next = _pr_GCLockHook;
00172           _pr_GCLockHook->prev = _pr_GCLockHook;
00173         }
00174 
00175         rf->next = _pr_GCLockHook;
00176         rf->prev = _pr_GCLockHook->prev;
00177         _pr_GCLockHook->prev->next = rf;
00178         _pr_GCLockHook->prev = rf;
00179        UNLOCK_GC();
00180        return 0;
00181     }
00182     return -1;
00183 }
00184 
00185 /*
00186 PR_IMPLEMENT(void) PR_SetGCLockHook(GCLockHook *hook, void *arg)
00187 {
00188     LOCK_GC();
00189     _pr_GCLockHook = hook;
00190     _pr_GCLockHookArg2 = arg;
00191     UNLOCK_GC();
00192 }
00193 
00194 PR_IMPLEMENT(void) PR_GetGCLockHook(GCLockHook **hook, void **arg)
00195 {
00196     LOCK_GC();
00197     *hook = _pr_GCLockHook;
00198     *arg = _pr_GCLockHookArg2;
00199     UNLOCK_GC();
00200 }
00201 */
00202 
00203   
00204 PR_IMPLEMENT(void) PR_SetBeginGCHook(GCBeginGCHook *hook, void *arg)
00205 {
00206     LOCK_GC();
00207     _pr_beginGCHook = hook;
00208     _pr_beginGCHookArg = arg;
00209     UNLOCK_GC();
00210 }
00211 
00212 PR_IMPLEMENT(void) PR_GetBeginGCHook(GCBeginGCHook **hook, void **arg)
00213 {
00214     LOCK_GC();
00215     *hook = _pr_beginGCHook;
00216     *arg = _pr_beginGCHookArg;
00217     UNLOCK_GC();
00218 }
00219 
00220 PR_IMPLEMENT(void) PR_SetEndGCHook(GCEndGCHook *hook, void *arg)
00221 {
00222     LOCK_GC();
00223     _pr_endGCHook = hook;
00224     _pr_endGCHookArg = arg;
00225     UNLOCK_GC();
00226 }
00227 
00228 PR_IMPLEMENT(void) PR_GetEndGCHook(GCEndGCHook **hook, void **arg)
00229 {
00230     LOCK_GC();
00231     *hook = _pr_endGCHook;
00232     *arg = _pr_endGCHookArg;
00233     UNLOCK_GC();
00234 }
00235 
00236 PR_IMPLEMENT(void) PR_SetBeginFinalizeHook(GCBeginFinalizeHook *hook, void *arg)
00237 {
00238     LOCK_GC();
00239     _pr_beginFinalizeHook = hook;
00240     _pr_beginFinalizeHookArg = arg;
00241     UNLOCK_GC();
00242 }
00243 
00244 PR_IMPLEMENT(void) PR_GetBeginFinalizeHook(GCBeginFinalizeHook **hook, 
00245                                            void **arg)
00246 {
00247     LOCK_GC();
00248     *hook = _pr_beginFinalizeHook;
00249     *arg = _pr_beginFinalizeHookArg;
00250     UNLOCK_GC();
00251 }
00252 
00253 PR_IMPLEMENT(void) PR_SetEndFinalizeHook(GCEndFinalizeHook *hook, void *arg)
00254 {
00255     LOCK_GC();
00256     _pr_endFinalizeHook = hook;
00257     _pr_endFinalizeHookArg = arg;
00258     UNLOCK_GC();
00259 }
00260 
00261 PR_IMPLEMENT(void) PR_GetEndFinalizeHook(GCEndFinalizeHook **hook, void **arg)
00262 {
00263     LOCK_GC();
00264     *hook = _pr_endFinalizeHook;
00265     *arg = _pr_endFinalizeHookArg;
00266     UNLOCK_GC();
00267 }
00268 
00269 #ifdef DEBUG
00270 #include "prprf.h"
00271 
00272 #if defined(WIN16)
00273 static FILE *tracefile = 0;
00274 #endif
00275 
00276 PR_IMPLEMENT(void) GCTrace(char *fmt, ...)
00277 {      
00278     va_list ap;
00279     char buf[400];
00280 
00281     va_start(ap, fmt);
00282     PR_vsnprintf(buf, sizeof(buf), fmt, ap);
00283     va_end(ap);
00284 #if defined(WIN16)
00285     if ( tracefile == 0 )
00286     {
00287         tracefile = fopen( "xxxGCtr", "w" );
00288     }
00289     fprintf(tracefile, "%s\n", buf );
00290     fflush(tracefile);
00291 #else
00292     PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("%s", buf));
00293 #endif
00294 }
00295 #endif
00296 
00297 void _PR_InitGC(PRWord flags)
00298 {
00299     static char firstTime = 1;
00300 
00301     if (!firstTime) return;
00302     firstTime = 0;
00303 
00304     _MD_InitGC();
00305 
00306     if (flags == 0) {
00307        char *ev = PR_GetEnv("GCLOG");
00308        if (ev && ev[0]) {
00309            flags = atoi(ev);
00310        }
00311     }
00312     _pr_gcData.flags = flags;
00313 
00314     _pr_gcData.lock = PR_NewMonitor();
00315 
00316     _pr_collectorTypes = (CollectorType*) PR_CALLOC(256 * sizeof(CollectorType));
00317 
00318     PR_RegisterRootFinder(ScanThreads, "scan threads", 0);
00319     PR_RegisterRootFinder(_PR_ScanFinalQueue, "scan final queue", 0);
00320 }
00321 
00322 extern void pr_FinalizeOnExit(void);
00323 
00324 #ifdef DEBUG
00325 #ifdef GC_STATS
00326 PR_PUBLIC_API(void) PR_PrintGCAllocStats(void);
00327 #endif 
00328 #endif 
00329   
00330 PR_IMPLEMENT(void) 
00331 PR_ShutdownGC(PRBool finalizeOnExit)
00332 {
00333     /* first finalize all the objects in the heap */
00334     if (finalizeOnExit) {
00335         pr_FinalizeOnExit();
00336     }
00337 
00338 #ifdef DEBUG
00339 #ifdef GC_STATS
00340     PR_PrintGCAllocStats();
00341 #endif /* GC_STATS */
00342 #endif /* DEBUG */
00343 
00344     /* then the chance for any future allocations */
00345 
00346     /* finally delete the gc heap */
00347 
00348     /* write me */
00349 }
00350 
00351 /******************************************************************************/