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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 #include "primpl.h"
     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;
    14 #ifdef DEBUG
    15 /*
    16 ** A variable that can be set via the debugger...
    17 */
    18 PRBool _pr_debugStacks = PR_FALSE;
    19 #endif
    21 /* How much space to leave between the stacks, at each end */
    22 #define REDZONE		(2 << _pr_pageShift)
    24 #define _PR_THREAD_STACK_PTR(_qp) \
    25     ((PRThreadStack*) ((char*) (_qp) - offsetof(PRThreadStack,links)))
    27 void _PR_InitStacks(void)
    28 {
    29     _pr_stackLock = PR_NewLock();
    30 }
    32 void _PR_CleanupStacks(void)
    33 {
    34     if (_pr_stackLock) {
    35         PR_DestroyLock(_pr_stackLock);
    36         _pr_stackLock = NULL;
    37     }
    38 }
    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;
    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);
    67 	/* Give platform OS to clear out the stack for debugging */
    68 	_PR_MD_CLEAR_STACK(ts);
    70 	_pr_numFreeStacks--;
    71 	_PR_DestroySegment(ts->seg);
    72 	PR_DELETE(ts);
    73     }
    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);
   105     if (!ts) {
   106 	/* Make a new thread stack object. */
   107 	ts = PR_NEWZAP(PRThreadStack);
   108 	if (!ts) {
   109 	    return NULL;
   110 	}
   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 	}
   126   done:
   127     ts->allocBase = (char*)ts->seg->vaddr;
   128     ts->flags = _PR_STACK_MAPPED;
   129     ts->stackSize = stackSize;
   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
   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));
   145     _PR_MD_INIT_STACK(ts,REDZONE);
   147     return ts;
   148 }
   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     }
   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 }

mercurial