| OLD | NEW |
| (Empty) |
| 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
| 2 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 5 | |
| 6 #include "primpl.h" | |
| 7 | |
| 8 /* List of free stack virtual memory chunks */ | |
| 9 PRLock *_pr_stackLock; | |
| 10 PRCList _pr_freeStacks = PR_INIT_STATIC_CLIST(&_pr_freeStacks); | |
| 11 PRIntn _pr_numFreeStacks; | |
| 12 PRIntn _pr_maxFreeStacks = 4; | |
| 13 | |
| 14 #ifdef DEBUG | |
| 15 /* | |
| 16 ** A variable that can be set via the debugger... | |
| 17 */ | |
| 18 PRBool _pr_debugStacks = PR_FALSE; | |
| 19 #endif | |
| 20 | |
| 21 /* How much space to leave between the stacks, at each end */ | |
| 22 #define REDZONE (2 << _pr_pageShift) | |
| 23 | |
| 24 #define _PR_THREAD_STACK_PTR(_qp) \ | |
| 25 ((PRThreadStack*) ((char*) (_qp) - offsetof(PRThreadStack,links))) | |
| 26 | |
| 27 void _PR_InitStacks(void) | |
| 28 { | |
| 29 _pr_stackLock = PR_NewLock(); | |
| 30 } | |
| 31 | |
| 32 void _PR_CleanupStacks(void) | |
| 33 { | |
| 34 if (_pr_stackLock) { | |
| 35 PR_DestroyLock(_pr_stackLock); | |
| 36 _pr_stackLock = NULL; | |
| 37 } | |
| 38 } | |
| 39 | |
| 40 /* | |
| 41 ** Allocate a stack for a thread. | |
| 42 */ | |
| 43 PRThreadStack *_PR_NewStack(PRUint32 stackSize) | |
| 44 { | |
| 45 PRCList *qp; | |
| 46 PRThreadStack *ts; | |
| 47 PRThread *thr; | |
| 48 | |
| 49 /* | |
| 50 ** Trim the list of free stacks. Trim it backwards, tossing out the | |
| 51 ** oldest stack found first (this way more recent stacks have a | |
| 52 ** chance of being present in the data cache). | |
| 53 */ | |
| 54 PR_Lock(_pr_stackLock); | |
| 55 qp = _pr_freeStacks.prev; | |
| 56 while ((_pr_numFreeStacks > _pr_maxFreeStacks) && (qp != &_pr_freeStacks)) { | |
| 57 ts = _PR_THREAD_STACK_PTR(qp); | |
| 58 thr = _PR_THREAD_STACK_TO_PTR(ts); | |
| 59 qp = qp->prev; | |
| 60 /* | |
| 61 * skip stacks which are still being used | |
| 62 */ | |
| 63 if (thr->no_sched) | |
| 64 continue; | |
| 65 PR_REMOVE_LINK(&ts->links); | |
| 66 | |
| 67 /* Give platform OS to clear out the stack for debugging */ | |
| 68 _PR_MD_CLEAR_STACK(ts); | |
| 69 | |
| 70 _pr_numFreeStacks--; | |
| 71 _PR_DestroySegment(ts->seg); | |
| 72 PR_DELETE(ts); | |
| 73 } | |
| 74 | |
| 75 /* | |
| 76 ** Find a free thread stack. This searches the list of free'd up | |
| 77 ** virtually mapped thread stacks. | |
| 78 */ | |
| 79 qp = _pr_freeStacks.next; | |
| 80 ts = 0; | |
| 81 while (qp != &_pr_freeStacks) { | |
| 82 ts = _PR_THREAD_STACK_PTR(qp); | |
| 83 thr = _PR_THREAD_STACK_TO_PTR(ts); | |
| 84 qp = qp->next; | |
| 85 /* | |
| 86 * skip stacks which are still being used | |
| 87 */ | |
| 88 if ((!(thr->no_sched)) && ((ts->allocSize - 2*REDZONE) >= stackSize)) { | |
| 89 /* | |
| 90 ** Found a stack that is not in use and is big enough. Change | |
| 91 ** stackSize to fit it. | |
| 92 */ | |
| 93 stackSize = ts->allocSize - 2*REDZONE; | |
| 94 PR_REMOVE_LINK(&ts->links); | |
| 95 _pr_numFreeStacks--; | |
| 96 ts->links.next = 0; | |
| 97 ts->links.prev = 0; | |
| 98 PR_Unlock(_pr_stackLock); | |
| 99 goto done; | |
| 100 } | |
| 101 ts = 0; | |
| 102 } | |
| 103 PR_Unlock(_pr_stackLock); | |
| 104 | |
| 105 if (!ts) { | |
| 106 /* Make a new thread stack object. */ | |
| 107 ts = PR_NEWZAP(PRThreadStack); | |
| 108 if (!ts) { | |
| 109 return NULL; | |
| 110 } | |
| 111 | |
| 112 /* | |
| 113 ** Assign some of the virtual space to the new stack object. We | |
| 114 ** may not get that piece of VM, but if nothing else we will | |
| 115 ** advance the pointer so we don't collide (unless the OS screws | |
| 116 ** up). | |
| 117 */ | |
| 118 ts->allocSize = stackSize + 2*REDZONE; | |
| 119 ts->seg = _PR_NewSegment(ts->allocSize, 0); | |
| 120 if (!ts->seg) { | |
| 121 PR_DELETE(ts); | |
| 122 return NULL; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 done: | |
| 127 ts->allocBase = (char*)ts->seg->vaddr; | |
| 128 ts->flags = _PR_STACK_MAPPED; | |
| 129 ts->stackSize = stackSize; | |
| 130 | |
| 131 #ifdef HAVE_STACK_GROWING_UP | |
| 132 ts->stackTop = ts->allocBase + REDZONE; | |
| 133 ts->stackBottom = ts->stackTop + stackSize; | |
| 134 #else | |
| 135 ts->stackBottom = ts->allocBase + REDZONE; | |
| 136 ts->stackTop = ts->stackBottom + stackSize; | |
| 137 #endif | |
| 138 | |
| 139 PR_LOG(_pr_thread_lm, PR_LOG_NOTICE, | |
| 140 ("thread stack: base=0x%x limit=0x%x bottom=0x%x top=0x%x\n", | |
| 141 ts->allocBase, ts->allocBase + ts->allocSize - 1, | |
| 142 ts->allocBase + REDZONE, | |
| 143 ts->allocBase + REDZONE + stackSize - 1)); | |
| 144 | |
| 145 _PR_MD_INIT_STACK(ts,REDZONE); | |
| 146 | |
| 147 return ts; | |
| 148 } | |
| 149 | |
| 150 /* | |
| 151 ** Free the stack for the current thread | |
| 152 */ | |
| 153 void _PR_FreeStack(PRThreadStack *ts) | |
| 154 { | |
| 155 if (!ts) { | |
| 156 return; | |
| 157 } | |
| 158 if (ts->flags & _PR_STACK_PRIMORDIAL) { | |
| 159 PR_DELETE(ts); | |
| 160 return; | |
| 161 } | |
| 162 | |
| 163 /* | |
| 164 ** Put the stack on the free list. This is done because we are still | |
| 165 ** using the stack. Next time a thread is created we will trim the | |
| 166 ** list down; it's safe to do it then because we will have had to | |
| 167 ** context switch to a live stack before another thread can be | |
| 168 ** created. | |
| 169 */ | |
| 170 PR_Lock(_pr_stackLock); | |
| 171 PR_APPEND_LINK(&ts->links, _pr_freeStacks.prev); | |
| 172 _pr_numFreeStacks++; | |
| 173 PR_Unlock(_pr_stackLock); | |
| 174 } | |
| OLD | NEW |