1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Netscape Portable Runtime (NSPR).
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "prlog.h"
39 : #include "prthread.h"
40 : #include "private/pprthred.h"
41 : #include "primpl.h"
42 :
43 : PR_IMPLEMENT(PRWord *)
44 0 : PR_GetGCRegisters(PRThread *t, int isCurrent, int *np)
45 : {
46 0 : return _MD_HomeGCRegisters(t, isCurrent, np);
47 : }
48 :
49 : PR_IMPLEMENT(PRStatus)
50 0 : PR_ThreadScanStackPointers(PRThread* t,
51 : PRScanStackFun scanFun, void* scanClosure)
52 : {
53 0 : PRThread* current = PR_GetCurrentThread();
54 : PRWord *sp, *esp, *p0;
55 : int n;
56 : void **ptd;
57 : PRStatus status;
58 : PRUint32 index;
59 : int stack_end;
60 :
61 : /*
62 : ** Store the thread's registers in the thread structure so the GC
63 : ** can scan them. Then scan them.
64 : */
65 0 : p0 = _MD_HomeGCRegisters(t, t == current, &n);
66 0 : status = scanFun(t, (void**)p0, n, scanClosure);
67 0 : if (status != PR_SUCCESS)
68 0 : return status;
69 :
70 : /* Scan the C stack for pointers into the GC heap */
71 : #if defined(XP_PC) && defined(WIN16)
72 : /*
73 : ** Under WIN16, the stack of the current thread is always mapped into
74 : ** the "task stack" (at SS:xxxx). So, if t is the current thread, scan
75 : ** the "task stack". Otherwise, scan the "cached stack" of the inactive
76 : ** thread...
77 : */
78 : if (t == current) {
79 : sp = (PRWord*) &stack_end;
80 : esp = (PRWord*) _pr_top_of_task_stack;
81 :
82 : PR_ASSERT(sp <= esp);
83 : } else {
84 : sp = (PRWord*) PR_GetSP(t);
85 : esp = (PRWord*) t->stack->stackTop;
86 :
87 : PR_ASSERT((t->stack->stackSize == 0) ||
88 : ((sp > (PRWord*)t->stack->stackBottom) &&
89 : (sp <= (PRWord*)t->stack->stackTop)));
90 : }
91 : #else /* ! WIN16 */
92 : #ifdef HAVE_STACK_GROWING_UP
93 : if (t == current) {
94 : esp = (PRWord*) &stack_end;
95 : } else {
96 : esp = (PRWord*) PR_GetSP(t);
97 : }
98 : sp = (PRWord*) t->stack->stackTop;
99 : if (t->stack->stackSize) {
100 : PR_ASSERT((esp > (PRWord*)t->stack->stackTop) &&
101 : (esp < (PRWord*)t->stack->stackBottom));
102 : }
103 : #else /* ! HAVE_STACK_GROWING_UP */
104 0 : if (t == current) {
105 0 : sp = (PRWord*) &stack_end;
106 : } else {
107 0 : sp = (PRWord*) PR_GetSP(t);
108 : }
109 0 : esp = (PRWord*) t->stack->stackTop;
110 0 : if (t->stack->stackSize) {
111 0 : PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) &&
112 : (sp < (PRWord*)t->stack->stackTop));
113 : }
114 : #endif /* ! HAVE_STACK_GROWING_UP */
115 : #endif /* ! WIN16 */
116 :
117 : #if defined(WIN16)
118 : {
119 : prword_t scan;
120 : prword_t limit;
121 :
122 : scan = (prword_t) sp;
123 : limit = (prword_t) esp;
124 : while (scan < limit) {
125 : prword_t *test;
126 :
127 : test = *((prword_t **)scan);
128 : status = scanFun(t, (void**)&test, 1, scanClosure);
129 : if (status != PR_SUCCESS)
130 : return status;
131 : scan += sizeof(char);
132 : }
133 : }
134 : #else
135 0 : if (sp < esp) {
136 0 : status = scanFun(t, (void**)sp, esp - sp, scanClosure);
137 0 : if (status != PR_SUCCESS)
138 0 : return status;
139 : }
140 : #endif
141 :
142 : /*
143 : ** Mark all of the per-thread-data items attached to this thread
144 : **
145 : ** The execution environment better be accounted for otherwise it
146 : ** will be collected
147 : */
148 0 : status = scanFun(t, (void**)&t->environment, 1, scanClosure);
149 0 : if (status != PR_SUCCESS)
150 0 : return status;
151 :
152 : /* if thread is not allocated on stack, this is redundant. */
153 0 : ptd = t->privateData;
154 0 : for (index = 0; index < t->tpdLength; index++, ptd++) {
155 0 : status = scanFun(t, (void**)ptd, 1, scanClosure);
156 0 : if (status != PR_SUCCESS)
157 0 : return status;
158 : }
159 :
160 0 : return PR_SUCCESS;
161 : }
162 :
163 : /* transducer for PR_EnumerateThreads */
164 : typedef struct PRScanStackData {
165 : PRScanStackFun scanFun;
166 : void* scanClosure;
167 : } PRScanStackData;
168 :
169 : static PRStatus PR_CALLBACK
170 0 : pr_ScanStack(PRThread* t, int i, void* arg)
171 : {
172 0 : PRScanStackData* data = (PRScanStackData*)arg;
173 0 : return PR_ThreadScanStackPointers(t, data->scanFun, data->scanClosure);
174 : }
175 :
176 : PR_IMPLEMENT(PRStatus)
177 0 : PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure)
178 : {
179 : PRScanStackData data;
180 0 : data.scanFun = scanFun;
181 0 : data.scanClosure = scanClosure;
182 0 : return PR_EnumerateThreads(pr_ScanStack, &data);
183 : }
184 :
185 : PR_IMPLEMENT(PRUword)
186 0 : PR_GetStackSpaceLeft(PRThread* t)
187 : {
188 0 : PRThread *current = PR_GetCurrentThread();
189 : PRWord *sp, *esp;
190 : int stack_end;
191 :
192 : #if defined(WIN16)
193 : /*
194 : ** Under WIN16, the stack of the current thread is always mapped into
195 : ** the "task stack" (at SS:xxxx). So, if t is the current thread, scan
196 : ** the "task stack". Otherwise, scan the "cached stack" of the inactive
197 : ** thread...
198 : */
199 : if (t == current) {
200 : sp = (PRWord*) &stack_end;
201 : esp = (PRWord*) _pr_top_of_task_stack;
202 :
203 : PR_ASSERT(sp <= esp);
204 : } else {
205 : sp = (PRWord*) PR_GetSP(t);
206 : esp = (PRWord*) t->stack->stackTop;
207 :
208 : PR_ASSERT((t->stack->stackSize == 0) ||
209 : ((sp > (PRWord*)t->stack->stackBottom) &&
210 : (sp <= (PRWord*)t->stack->stackTop)));
211 : }
212 : #else /* ! WIN16 */
213 : #ifdef HAVE_STACK_GROWING_UP
214 : if (t == current) {
215 : esp = (PRWord*) &stack_end;
216 : } else {
217 : esp = (PRWord*) PR_GetSP(t);
218 : }
219 : sp = (PRWord*) t->stack->stackTop;
220 : if (t->stack->stackSize) {
221 : PR_ASSERT((esp > (PRWord*)t->stack->stackTop) &&
222 : (esp < (PRWord*)t->stack->stackBottom));
223 : }
224 : #else /* ! HAVE_STACK_GROWING_UP */
225 0 : if (t == current) {
226 0 : sp = (PRWord*) &stack_end;
227 : } else {
228 0 : sp = (PRWord*) PR_GetSP(t);
229 : }
230 0 : esp = (PRWord*) t->stack->stackTop;
231 0 : if (t->stack->stackSize) {
232 0 : PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) &&
233 : (sp < (PRWord*)t->stack->stackTop));
234 : }
235 : #endif /* ! HAVE_STACK_GROWING_UP */
236 : #endif /* ! WIN16 */
237 0 : return (PRUword)t->stack->stackSize - ((PRWord)esp - (PRWord)sp);
238 : }
|