The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/servers/pm/break.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* The MINIX model of memory allocation reserves a fixed amount of memory for
    2  * the combined text, data, and stack segments.  The amount used for a child
    3  * process created by FORK is the same as the parent had.  If the child does
    4  * an EXEC later, the new size is taken from the header of the file EXEC'ed.
    5  *
    6  * The layout in memory consists of the text segment, followed by the data
    7  * segment, followed by a gap (unused memory), followed by the stack segment.
    8  * The data segment grows upward and the stack grows downward, so each can
    9  * take memory from the gap.  If they meet, the process must be killed.  The
   10  * procedures in this file deal with the growth of the data and stack segments.
   11  *
   12  * The entry points into this file are:
   13  *   do_brk:      BRK/SBRK system calls to grow or shrink the data segment
   14  *   adjust:      see if a proposed segment adjustment is allowed
   15  *   size_ok:     see if the segment sizes are feasible (i86 only)
   16  */
   17 
   18 #include "pm.h"
   19 #include <signal.h>
   20 #include "mproc.h"
   21 #include "param.h"
   22 
   23 #define DATA_CHANGED       1    /* flag value when data segment size changed */
   24 #define STACK_CHANGED      2    /* flag value when stack size changed */
   25 
   26 /*===========================================================================*
   27  *                              do_brk                                       *
   28  *===========================================================================*/
   29 PUBLIC int do_brk()
   30 {
   31 /* Perform the brk(addr) system call.
   32  *
   33  * The call is complicated by the fact that on some machines (e.g., 8088),
   34  * the stack pointer can grow beyond the base of the stack segment without
   35  * anybody noticing it.
   36  * The parameter, 'addr' is the new virtual address in D space.
   37  */
   38 
   39   register struct mproc *rmp;
   40   int r;
   41   vir_bytes v, new_sp;
   42   vir_clicks new_clicks;
   43 
   44   rmp = mp;
   45   v = (vir_bytes) m_in.addr;
   46   new_clicks = (vir_clicks) ( ((long) v + CLICK_SIZE - 1) >> CLICK_SHIFT);
   47   if (new_clicks < rmp->mp_seg[D].mem_vir) {
   48         rmp->mp_reply.reply_ptr = (char *) -1;
   49         return(ENOMEM);
   50   }
   51   new_clicks -= rmp->mp_seg[D].mem_vir;
   52   if ((r=get_stack_ptr(who, &new_sp)) != OK)    /* ask kernel for sp value */
   53         panic(__FILE__,"couldn't get stack pointer", r);
   54   r = adjust(rmp, new_clicks, new_sp);
   55   rmp->mp_reply.reply_ptr = (r == OK ? m_in.addr : (char *) -1);
   56   return(r);                    /* return new address or -1 */
   57 }
   58 
   59 /*===========================================================================*
   60  *                              adjust                                       *
   61  *===========================================================================*/
   62 PUBLIC int adjust(rmp, data_clicks, sp)
   63 register struct mproc *rmp;     /* whose memory is being adjusted? */
   64 vir_clicks data_clicks;         /* how big is data segment to become? */
   65 vir_bytes sp;                   /* new value of sp */
   66 {
   67 /* See if data and stack segments can coexist, adjusting them if need be.
   68  * Memory is never allocated or freed.  Instead it is added or removed from the
   69  * gap between data segment and stack segment.  If the gap size becomes
   70  * negative, the adjustment of data or stack fails and ENOMEM is returned.
   71  */
   72 
   73   register struct mem_map *mem_sp, *mem_dp;
   74   vir_clicks sp_click, gap_base, lower, old_clicks;
   75   int changed, r, ft;
   76   long base_of_stack, delta;    /* longs avoid certain problems */
   77 
   78   mem_dp = &rmp->mp_seg[D];     /* pointer to data segment map */
   79   mem_sp = &rmp->mp_seg[S];     /* pointer to stack segment map */
   80   changed = 0;                  /* set when either segment changed */
   81 
   82   if (mem_sp->mem_len == 0) return(OK); /* don't bother init */
   83 
   84   /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
   85   base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
   86   sp_click = sp >> CLICK_SHIFT; /* click containing sp */
   87   if (sp_click >= base_of_stack) return(ENOMEM);        /* sp too high */
   88 
   89   /* Compute size of gap between stack and data segments. */
   90   delta = (long) mem_sp->mem_vir - (long) sp_click;
   91   lower = (delta > 0 ? sp_click : mem_sp->mem_vir);
   92 
   93   /* Add a safety margin for future stack growth. Impossible to do right. */
   94 #define SAFETY_BYTES  (384 * sizeof(char *))
   95 #define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
   96   gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
   97   if (lower < gap_base) return(ENOMEM); /* data and stack collided */
   98 
   99   /* Update data length (but not data orgin) on behalf of brk() system call. */
  100   old_clicks = mem_dp->mem_len;
  101   if (data_clicks != mem_dp->mem_len) {
  102         mem_dp->mem_len = data_clicks;
  103         changed |= DATA_CHANGED;
  104   }
  105 
  106   /* Update stack length and origin due to change in stack pointer. */
  107   if (delta > 0) {
  108         mem_sp->mem_vir -= delta;
  109         mem_sp->mem_phys -= delta;
  110         mem_sp->mem_len += delta;
  111         changed |= STACK_CHANGED;
  112   }
  113 
  114   /* Do the new data and stack segment sizes fit in the address space? */
  115   ft = (rmp->mp_flags & SEPARATE);
  116 #if (CHIP == INTEL && _WORD_SIZE == 2)
  117   r = size_ok(ft, rmp->mp_seg[T].mem_len, rmp->mp_seg[D].mem_len, 
  118        rmp->mp_seg[S].mem_len, rmp->mp_seg[D].mem_vir, rmp->mp_seg[S].mem_vir);
  119 #else
  120   r = (rmp->mp_seg[D].mem_vir + rmp->mp_seg[D].mem_len > 
  121           rmp->mp_seg[S].mem_vir) ? ENOMEM : OK;
  122 #endif
  123   if (r == OK) {
  124         if (changed) sys_newmap((int)(rmp - mproc), rmp->mp_seg);
  125         return(OK);
  126   }
  127 
  128   /* New sizes don't fit or require too many page/segment registers. Restore.*/
  129   if (changed & DATA_CHANGED) mem_dp->mem_len = old_clicks;
  130   if (changed & STACK_CHANGED) {
  131         mem_sp->mem_vir += delta;
  132         mem_sp->mem_phys += delta;
  133         mem_sp->mem_len -= delta;
  134   }
  135   return(ENOMEM);
  136 }
  137 
  138 #if (CHIP == INTEL && _WORD_SIZE == 2)
  139 /*===========================================================================*
  140  *                              size_ok                                      *
  141  *===========================================================================*/
  142 PUBLIC int size_ok(file_type, tc, dc, sc, dvir, s_vir)
  143 int file_type;                  /* SEPARATE or 0 */
  144 vir_clicks tc;                  /* text size in clicks */
  145 vir_clicks dc;                  /* data size in clicks */
  146 vir_clicks sc;                  /* stack size in clicks */
  147 vir_clicks dvir;                /* virtual address for start of data seg */
  148 vir_clicks s_vir;               /* virtual address for start of stack seg */
  149 {
  150 /* Check to see if the sizes are feasible and enough segmentation registers
  151  * exist.  On a machine with eight 8K pages, text, data, stack sizes of
  152  * (32K, 16K, 16K) will fit, but (33K, 17K, 13K) will not, even though the
  153  * former is bigger (64K) than the latter (63K).  Even on the 8088 this test
  154  * is needed, since the data and stack may not exceed 4096 clicks.
  155  * Note this is not used for 32-bit Intel Minix, the test is done in-line.
  156  */
  157 
  158   int pt, pd, ps;               /* segment sizes in pages */
  159 
  160   pt = ( (tc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE;
  161   pd = ( (dc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE;
  162   ps = ( (sc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE;
  163 
  164   if (file_type == SEPARATE) {
  165         if (pt > MAX_PAGES || pd + ps > MAX_PAGES) return(ENOMEM);
  166   } else {
  167         if (pt + pd + ps > MAX_PAGES) return(ENOMEM);
  168   }
  169 
  170   if (dvir + dc > s_vir) return(ENOMEM);
  171 
  172   return(OK);
  173 }
  174 #endif
  175 

Cache object: d15098f59ffcf442d5f8049ffeed0cd0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.