home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / threads / combined / prustack.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  4.9 KB  |  184 lines

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