Back to index

lightning-sunbird  0.9+nobinonly
prthinfo.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 "prlog.h"
00039 #include "prthread.h"
00040 #ifdef XP_MAC
00041 #include "pprthred.h"
00042 #else
00043 #include "private/pprthred.h"
00044 #endif
00045 #include "primpl.h"
00046 
00047 PR_IMPLEMENT(PRWord *)
00048 PR_GetGCRegisters(PRThread *t, int isCurrent, int *np)
00049 {
00050     return _MD_HomeGCRegisters(t, isCurrent, np);
00051 }
00052 
00053 PR_IMPLEMENT(PRStatus)
00054 PR_ThreadScanStackPointers(PRThread* t,
00055                            PRScanStackFun scanFun, void* scanClosure)
00056 {
00057     PRThread* current = PR_GetCurrentThread();
00058     PRWord *sp, *esp, *p0;
00059     int n;
00060     void **ptd;
00061     PRStatus status;
00062     PRUint32 index;
00063     int stack_end;
00064 
00065     /*
00066     ** Store the thread's registers in the thread structure so the GC
00067     ** can scan them. Then scan them.
00068     */
00069     p0 = _MD_HomeGCRegisters(t, t == current, &n);
00070     status = scanFun(t, (void**)p0, n, scanClosure);
00071     if (status != PR_SUCCESS)
00072         return status;
00073 
00074     /* Scan the C stack for pointers into the GC heap */
00075 #if defined(XP_PC) && defined(WIN16)
00076     /*
00077     ** Under WIN16, the stack of the current thread is always mapped into
00078     ** the "task stack" (at SS:xxxx).  So, if t is the current thread, scan
00079     ** the "task stack".  Otherwise, scan the "cached stack" of the inactive
00080     ** thread...
00081     */
00082     if (t == current) {
00083         sp  = (PRWord*) &stack_end;
00084         esp = (PRWord*) _pr_top_of_task_stack;
00085 
00086         PR_ASSERT(sp <= esp);
00087     } else {
00088         sp  = (PRWord*) PR_GetSP(t);
00089         esp = (PRWord*) t->stack->stackTop;
00090 
00091         PR_ASSERT((t->stack->stackSize == 0) ||
00092                   ((sp >  (PRWord*)t->stack->stackBottom) &&
00093                    (sp <= (PRWord*)t->stack->stackTop)));
00094     }
00095 #else   /* ! WIN16 */
00096 #ifdef HAVE_STACK_GROWING_UP
00097     if (t == current) {
00098         esp = (PRWord*) &stack_end;
00099     } else {
00100         esp = (PRWord*) PR_GetSP(t);
00101     }
00102     sp = (PRWord*) t->stack->stackTop;
00103     if (t->stack->stackSize) {
00104         PR_ASSERT((esp > (PRWord*)t->stack->stackTop) &&
00105                   (esp < (PRWord*)t->stack->stackBottom));
00106     }
00107 #else   /* ! HAVE_STACK_GROWING_UP */
00108     if (t == current) {
00109         sp = (PRWord*) &stack_end;
00110     } else {
00111         sp = (PRWord*) PR_GetSP(t);
00112     }
00113     esp = (PRWord*) t->stack->stackTop;
00114     if (t->stack->stackSize) {
00115         PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) &&
00116                   (sp < (PRWord*)t->stack->stackTop));
00117     }
00118 #endif  /* ! HAVE_STACK_GROWING_UP */
00119 #endif  /* ! WIN16 */
00120 
00121 #if defined(WIN16)
00122     {
00123         prword_t scan;
00124         prword_t limit;
00125         
00126         scan = (prword_t) sp;
00127         limit = (prword_t) esp;
00128         while (scan < limit) {
00129             prword_t *test;
00130 
00131             test = *((prword_t **)scan);
00132             status = scanFun(t, (void**)&test, 1, scanClosure);
00133             if (status != PR_SUCCESS)
00134                 return status;
00135             scan += sizeof(char);
00136         }
00137     }
00138 #else
00139     if (sp < esp) {
00140         status = scanFun(t, (void**)sp, esp - sp, scanClosure);
00141         if (status != PR_SUCCESS)
00142             return status;
00143     }
00144 #endif
00145 
00146     /*
00147     ** Mark all of the per-thread-data items attached to this thread
00148     **
00149     ** The execution environment better be accounted for otherwise it
00150     ** will be collected
00151     */
00152     status = scanFun(t, (void**)&t->environment, 1, scanClosure);
00153     if (status != PR_SUCCESS)
00154         return status;
00155 
00156 #ifndef GC_LEAK_DETECTOR
00157     /* if thread is not allocated on stack, this is redundant. */
00158     ptd = t->privateData;
00159     for (index = 0; index < t->tpdLength; index++, ptd++) {
00160         status = scanFun(t, (void**)ptd, 1, scanClosure);
00161         if (status != PR_SUCCESS)
00162             return status;
00163     }
00164 #endif
00165     
00166     return PR_SUCCESS;
00167 }
00168 
00169 /* transducer for PR_EnumerateThreads */
00170 typedef struct PRScanStackData {
00171     PRScanStackFun      scanFun;
00172     void*               scanClosure;
00173 } PRScanStackData;
00174 
00175 static PRStatus PR_CALLBACK
00176 pr_ScanStack(PRThread* t, int i, void* arg)
00177 {
00178 #if defined(XP_MAC)
00179 #pragma unused (i)
00180 #endif
00181     PRScanStackData* data = (PRScanStackData*)arg;
00182     return PR_ThreadScanStackPointers(t, data->scanFun, data->scanClosure);
00183 }
00184 
00185 PR_IMPLEMENT(PRStatus)
00186 PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure)
00187 {
00188     PRScanStackData data;
00189     data.scanFun = scanFun;
00190     data.scanClosure = scanClosure;
00191     return PR_EnumerateThreads(pr_ScanStack, &data);
00192 }
00193 
00194 PR_IMPLEMENT(PRUword)
00195 PR_GetStackSpaceLeft(PRThread* t)
00196 {
00197     PRThread *current = PR_CurrentThread();
00198     PRWord *sp, *esp;
00199     int stack_end;
00200 
00201 #if defined(WIN16)
00202     /*
00203     ** Under WIN16, the stack of the current thread is always mapped into
00204     ** the "task stack" (at SS:xxxx).  So, if t is the current thread, scan
00205     ** the "task stack".  Otherwise, scan the "cached stack" of the inactive
00206     ** thread...
00207     */
00208     if (t == current) {
00209         sp  = (PRWord*) &stack_end;
00210         esp = (PRWord*) _pr_top_of_task_stack;
00211 
00212         PR_ASSERT(sp <= esp);
00213     } else {
00214         sp  = (PRWord*) PR_GetSP(t);
00215         esp = (PRWord*) t->stack->stackTop;
00216 
00217        PR_ASSERT((t->stack->stackSize == 0) ||
00218                  ((sp >  (PRWord*)t->stack->stackBottom) &&
00219                 (sp <= (PRWord*)t->stack->stackTop)));
00220     }
00221 #else   /* ! WIN16 */
00222 #ifdef HAVE_STACK_GROWING_UP
00223     if (t == current) {
00224         esp = (PRWord*) &stack_end;
00225     } else {
00226         esp = (PRWord*) PR_GetSP(t);
00227     }
00228     sp = (PRWord*) t->stack->stackTop;
00229     if (t->stack->stackSize) {
00230         PR_ASSERT((esp > (PRWord*)t->stack->stackTop) &&
00231                   (esp < (PRWord*)t->stack->stackBottom));
00232     }
00233 #else   /* ! HAVE_STACK_GROWING_UP */
00234     if (t == current) {
00235         sp = (PRWord*) &stack_end;
00236     } else {
00237         sp = (PRWord*) PR_GetSP(t);
00238     }
00239     esp = (PRWord*) t->stack->stackTop;
00240     if (t->stack->stackSize) {
00241        PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) &&
00242                 (sp < (PRWord*)t->stack->stackTop));
00243     }
00244 #endif  /* ! HAVE_STACK_GROWING_UP */
00245 #endif  /* ! WIN16 */
00246     return (PRUword)t->stack->stackSize - ((PRWord)esp - (PRWord)sp);
00247 }