nsprpub/pr/src/threads/combined/prustack.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/threads/combined/prustack.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,174 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "primpl.h"
    1.10 +
    1.11 +/* List of free stack virtual memory chunks */
    1.12 +PRLock *_pr_stackLock;
    1.13 +PRCList _pr_freeStacks = PR_INIT_STATIC_CLIST(&_pr_freeStacks);
    1.14 +PRIntn _pr_numFreeStacks;
    1.15 +PRIntn _pr_maxFreeStacks = 4;
    1.16 +
    1.17 +#ifdef DEBUG
    1.18 +/*
    1.19 +** A variable that can be set via the debugger...
    1.20 +*/
    1.21 +PRBool _pr_debugStacks = PR_FALSE;
    1.22 +#endif
    1.23 +
    1.24 +/* How much space to leave between the stacks, at each end */
    1.25 +#define REDZONE		(2 << _pr_pageShift)
    1.26 +
    1.27 +#define _PR_THREAD_STACK_PTR(_qp) \
    1.28 +    ((PRThreadStack*) ((char*) (_qp) - offsetof(PRThreadStack,links)))
    1.29 +
    1.30 +void _PR_InitStacks(void)
    1.31 +{
    1.32 +    _pr_stackLock = PR_NewLock();
    1.33 +}
    1.34 +
    1.35 +void _PR_CleanupStacks(void)
    1.36 +{
    1.37 +    if (_pr_stackLock) {
    1.38 +        PR_DestroyLock(_pr_stackLock);
    1.39 +        _pr_stackLock = NULL;
    1.40 +    }
    1.41 +}
    1.42 +
    1.43 +/*
    1.44 +** Allocate a stack for a thread.
    1.45 +*/
    1.46 +PRThreadStack *_PR_NewStack(PRUint32 stackSize)
    1.47 +{
    1.48 +    PRCList *qp;
    1.49 +    PRThreadStack *ts;
    1.50 +    PRThread *thr;
    1.51 +
    1.52 +    /*
    1.53 +    ** Trim the list of free stacks. Trim it backwards, tossing out the
    1.54 +    ** oldest stack found first (this way more recent stacks have a
    1.55 +    ** chance of being present in the data cache).
    1.56 +    */
    1.57 +    PR_Lock(_pr_stackLock);
    1.58 +    qp = _pr_freeStacks.prev;
    1.59 +    while ((_pr_numFreeStacks > _pr_maxFreeStacks) && (qp != &_pr_freeStacks)) {
    1.60 +	ts = _PR_THREAD_STACK_PTR(qp);
    1.61 +	thr = _PR_THREAD_STACK_TO_PTR(ts);
    1.62 +	qp = qp->prev;
    1.63 +	/*
    1.64 +	 * skip stacks which are still being used
    1.65 +	 */
    1.66 +	if (thr->no_sched)
    1.67 +		continue;
    1.68 +	PR_REMOVE_LINK(&ts->links);
    1.69 +
    1.70 +	/* Give platform OS to clear out the stack for debugging */
    1.71 +	_PR_MD_CLEAR_STACK(ts);
    1.72 +
    1.73 +	_pr_numFreeStacks--;
    1.74 +	_PR_DestroySegment(ts->seg);
    1.75 +	PR_DELETE(ts);
    1.76 +    }
    1.77 +
    1.78 +    /*
    1.79 +    ** Find a free thread stack. This searches the list of free'd up
    1.80 +    ** virtually mapped thread stacks.
    1.81 +    */
    1.82 +    qp = _pr_freeStacks.next;
    1.83 +    ts = 0;
    1.84 +    while (qp != &_pr_freeStacks) {
    1.85 +	ts = _PR_THREAD_STACK_PTR(qp);
    1.86 +	thr = _PR_THREAD_STACK_TO_PTR(ts);
    1.87 +	qp = qp->next;
    1.88 +	/*
    1.89 +	 * skip stacks which are still being used
    1.90 +	 */
    1.91 +	if ((!(thr->no_sched)) && ((ts->allocSize - 2*REDZONE) >= stackSize)) {
    1.92 +	    /*
    1.93 +	    ** Found a stack that is not in use and is big enough. Change
    1.94 +	    ** stackSize to fit it.
    1.95 +	    */
    1.96 +	    stackSize = ts->allocSize - 2*REDZONE;
    1.97 +	    PR_REMOVE_LINK(&ts->links);
    1.98 +	    _pr_numFreeStacks--;
    1.99 +	    ts->links.next = 0;
   1.100 +	    ts->links.prev = 0;
   1.101 +	    PR_Unlock(_pr_stackLock);
   1.102 +	    goto done;
   1.103 +	}
   1.104 +	ts = 0;
   1.105 +    }
   1.106 +    PR_Unlock(_pr_stackLock);
   1.107 +
   1.108 +    if (!ts) {
   1.109 +	/* Make a new thread stack object. */
   1.110 +	ts = PR_NEWZAP(PRThreadStack);
   1.111 +	if (!ts) {
   1.112 +	    return NULL;
   1.113 +	}
   1.114 +
   1.115 +	/*
   1.116 +	** Assign some of the virtual space to the new stack object. We
   1.117 +	** may not get that piece of VM, but if nothing else we will
   1.118 +	** advance the pointer so we don't collide (unless the OS screws
   1.119 +	** up).
   1.120 +	*/
   1.121 +	ts->allocSize = stackSize + 2*REDZONE;
   1.122 +	ts->seg = _PR_NewSegment(ts->allocSize, 0);
   1.123 +	if (!ts->seg) {
   1.124 +	    PR_DELETE(ts);
   1.125 +	    return NULL;
   1.126 +	}
   1.127 +	}
   1.128 +
   1.129 +  done:
   1.130 +    ts->allocBase = (char*)ts->seg->vaddr;
   1.131 +    ts->flags = _PR_STACK_MAPPED;
   1.132 +    ts->stackSize = stackSize;
   1.133 +
   1.134 +#ifdef HAVE_STACK_GROWING_UP
   1.135 +    ts->stackTop = ts->allocBase + REDZONE;
   1.136 +    ts->stackBottom = ts->stackTop + stackSize;
   1.137 +#else
   1.138 +    ts->stackBottom = ts->allocBase + REDZONE;
   1.139 +    ts->stackTop = ts->stackBottom + stackSize;
   1.140 +#endif
   1.141 +
   1.142 +    PR_LOG(_pr_thread_lm, PR_LOG_NOTICE,
   1.143 +	   ("thread stack: base=0x%x limit=0x%x bottom=0x%x top=0x%x\n",
   1.144 +	    ts->allocBase, ts->allocBase + ts->allocSize - 1,
   1.145 +	    ts->allocBase + REDZONE,
   1.146 +	    ts->allocBase + REDZONE + stackSize - 1));
   1.147 +	    
   1.148 +    _PR_MD_INIT_STACK(ts,REDZONE);
   1.149 +
   1.150 +    return ts;
   1.151 +}
   1.152 +
   1.153 +/*
   1.154 +** Free the stack for the current thread
   1.155 +*/
   1.156 +void _PR_FreeStack(PRThreadStack *ts)
   1.157 +{
   1.158 +    if (!ts) {
   1.159 +	return;
   1.160 +    }
   1.161 +    if (ts->flags & _PR_STACK_PRIMORDIAL) {
   1.162 +	PR_DELETE(ts);
   1.163 +	return;
   1.164 +    }
   1.165 +
   1.166 +    /*
   1.167 +    ** Put the stack on the free list. This is done because we are still
   1.168 +    ** using the stack. Next time a thread is created we will trim the
   1.169 +    ** list down; it's safe to do it then because we will have had to
   1.170 +    ** context switch to a live stack before another thread can be
   1.171 +    ** created.
   1.172 +    */
   1.173 +    PR_Lock(_pr_stackLock);
   1.174 +    PR_APPEND_LINK(&ts->links, _pr_freeStacks.prev);
   1.175 +    _pr_numFreeStacks++;
   1.176 +    PR_Unlock(_pr_stackLock);
   1.177 +}

mercurial