Back to index

glibc  2.9
brk.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991,92,93,94,95,96,97,99,2000 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <errno.h>
00020 #include <hurd.h>
00021 #include <hurd/resource.h>
00022 #include <cthreads.h>              /* For `struct mutex'.  */
00023 
00024 
00025 /* Initial maximum size of the data segment (this is arbitrary).  */
00026 #define       DATA_SIZE     (128 * 1024 * 1024)
00027 
00028 /* Up to the page including this address is allocated from the kernel.
00029    This address is the data resource limit.  */
00030 vm_address_t _hurd_data_end;
00031 
00032 /* Up to this address is actually available to the user.
00033    Pages beyond the one containing this address allow no access.  */
00034 vm_address_t _hurd_brk = 0;
00035 
00036 /* This name is used by the Linux crtbeginS.o for reasons you don't even
00037    want to think about it.  It's just easier to provide some definition for
00038    it than even to explain the braindamage involved.  */
00039 weak_alias (_hurd_brk, ___brk_addr)
00040 
00041 struct mutex _hurd_brk_lock;
00042 
00043 extern int __data_start, _end;
00044 weak_extern (__data_start)
00045 static vm_address_t static_data_start;
00046 
00047 
00048 /* Set the end of the process's data space to INADDR.
00049    Return 0 if successful, -1 if not.  */
00050 int
00051 __brk (void *inaddr)
00052 {
00053   int ret;
00054   HURD_CRITICAL_BEGIN;
00055   __mutex_lock (&_hurd_brk_lock);
00056   ret = _hurd_set_brk ((vm_address_t) inaddr);
00057   __mutex_unlock (&_hurd_brk_lock);
00058   HURD_CRITICAL_END;
00059   return ret;
00060 }
00061 weak_alias (__brk, brk)
00062 
00063 
00064 int
00065 _hurd_set_brk (vm_address_t addr)
00066 {
00067   error_t err;
00068   vm_address_t pagend = round_page (addr);
00069   vm_address_t pagebrk = round_page (_hurd_brk);
00070   long int rlimit;
00071 
00072   if (pagend <= pagebrk)
00073     {
00074       if (pagend < pagebrk)
00075        {
00076          /* XXX wish this were atomic... */
00077          /* First deallocate the memory to release its backing space.  */
00078          __vm_deallocate (__mach_task_self (), pagend, pagebrk - pagend);
00079          /* Now reallocate it with no access allowed.  */
00080          err = __vm_map (__mach_task_self (),
00081                        &pagend, pagebrk - pagend,
00082                        0, 0, MACH_PORT_NULL, 0, 0,
00083                        0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
00084                        VM_INHERIT_COPY);
00085          /* XXX what if error? */
00086        }
00087       _hurd_brk = addr;
00088       return 0;
00089     }
00090 
00091   __mutex_lock (&_hurd_rlimit_lock);
00092   rlimit = _hurd_rlimits[RLIMIT_DATA].rlim_cur;
00093   __mutex_unlock (&_hurd_rlimit_lock);
00094 
00095   if (addr - static_data_start > rlimit)
00096     {
00097       /* Need to increase the resource limit.  */
00098       errno = ENOMEM;
00099       return -1;
00100     }
00101 
00102   if (pagend > _hurd_data_end)
00103     {
00104       /* We didn't allocate enough space!  Hopefully we can get some more!  */
00105       err = __vm_allocate (__mach_task_self (), &pagebrk, pagend - pagebrk, 0);
00106       if (! err)
00107        _hurd_data_end = pagend;
00108     }
00109   else
00110     /* Make the memory accessible.  */
00111     err = __vm_protect (__mach_task_self (), pagebrk, pagend - pagebrk,
00112                      0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
00113 
00114   if (err)
00115     return __hurd_fail (err);
00116 
00117   _hurd_brk = addr;
00118   return 0;
00119 }
00120 
00121 static void
00122 init_brk (void)
00123 {
00124   vm_address_t pagend;
00125 
00126   __mutex_init (&_hurd_brk_lock);
00127 
00128   static_data_start = (vm_address_t) (&__data_start ?: &_end);
00129 
00130   /* If _hurd_brk is already set, don't change it.  The assumption is that
00131      it was set in a previous run before something like Emacs's unexec was
00132      called and dumped all the data up to the break at that point.  */
00133   if (_hurd_brk == 0)
00134     _hurd_brk = (vm_address_t) &_end;
00135 
00136   pagend = round_page (_hurd_brk);
00137 
00138   _hurd_data_end = round_page (static_data_start + DATA_SIZE);
00139 
00140   if (pagend < _hurd_data_end)
00141     {
00142       /* We use vm_map to allocate and change permissions atomically.  */
00143       if (__vm_map (__mach_task_self (), &pagend, _hurd_data_end - pagend,
00144                   0, 0, MACH_PORT_NULL, 0, 0,
00145                   0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
00146                   VM_INHERIT_COPY))
00147        /* Couldn't allocate the memory.  The break will be very short.  */
00148        _hurd_data_end = pagend;
00149     }
00150 
00151   (void) &init_brk;         /* Avoid ``defined but not used'' warning.  */
00152 }
00153 text_set_element (_hurd_preinit_hook, init_brk);