]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/mach/hurd/brk.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / sysdeps / mach / hurd / brk.c
index a96286b2d936fdfc16bedc561c3541f36d776771..8ff87913c38947e3e7e2e88240606b6bf0130a77 100644 (file)
@@ -1,31 +1,28 @@
-/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
+/* Copyright (C) 1991-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
 
-#include <ansidecl.h>
 #include <errno.h>
 #include <hurd.h>
 #include <hurd/resource.h>
 #include <cthreads.h>          /* For `struct mutex'.  */
 
 
-/* Initial maximum size of the data segment (32MB, which is arbitrary).  */
-#define        DATA_SIZE       (32 * 1024 * 1024)
-
+/* Initial maximum size of the data segment (this is arbitrary).  */
+#define        DATA_SIZE       (128 * 1024 * 1024)
 
 /* Up to the page including this address is allocated from the kernel.
    This address is the data resource limit.  */
@@ -33,17 +30,24 @@ vm_address_t _hurd_data_end;
 
 /* Up to this address is actually available to the user.
    Pages beyond the one containing this address allow no access.  */
-vm_address_t _hurd_brk;
+vm_address_t _hurd_brk = 0;
+
+/* This name is used by the Linux crtbeginS.o for reasons you don't even
+   want to think about it.  It's just easier to provide some definition for
+   it than even to explain the braindamage involved.  */
+weak_alias (_hurd_brk, ___brk_addr)
 
 struct mutex _hurd_brk_lock;
 
 extern int __data_start, _end;
+weak_extern (__data_start)
+static vm_address_t static_data_start;
 
 
 /* Set the end of the process's data space to INADDR.
    Return 0 if successful, -1 if not.  */
 int
-DEFUN(__brk, (inaddr), PTR inaddr)
+__brk (void *inaddr)
 {
   int ret;
   HURD_CRITICAL_BEGIN;
@@ -59,7 +63,7 @@ weak_alias (__brk, brk)
 int
 _hurd_set_brk (vm_address_t addr)
 {
-  error_t err;
+  error_t err = 0;
   vm_address_t pagend = round_page (addr);
   vm_address_t pagebrk = round_page (_hurd_brk);
   long int rlimit;
@@ -67,9 +71,18 @@ _hurd_set_brk (vm_address_t addr)
   if (pagend <= pagebrk)
     {
       if (pagend < pagebrk)
-       /* Make that memory inaccessible.  */
-       __vm_protect (__mach_task_self (), pagend, pagebrk - pagend,
-                     0, VM_PROT_NONE);
+       {
+         /* XXX wish this were atomic... */
+         /* First deallocate the memory to release its backing space.  */
+         __vm_deallocate (__mach_task_self (), pagend, pagebrk - pagend);
+         /* Now reallocate it with no access allowed.  */
+         err = __vm_map (__mach_task_self (),
+                         &pagend, pagebrk - pagend,
+                         0, 0, MACH_PORT_NULL, 0, 0,
+                         0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
+                         VM_INHERIT_COPY);
+         /* XXX what if error? */
+       }
       _hurd_brk = addr;
       return 0;
     }
@@ -78,20 +91,41 @@ _hurd_set_brk (vm_address_t addr)
   rlimit = _hurd_rlimits[RLIMIT_DATA].rlim_cur;
   __mutex_unlock (&_hurd_rlimit_lock);
 
-  if (addr - (vm_address_t) &__data_start > rlimit)
+  if (addr - static_data_start > rlimit)
     {
       /* Need to increase the resource limit.  */
       errno = ENOMEM;
       return -1;
     }
 
-  /* Make the memory accessible.  */
-  if (err = __vm_protect (__mach_task_self (), pagebrk, pagend - pagebrk,
-                         0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE))
+  if (pagend > _hurd_data_end)
     {
-      errno = err;
-      return -1;
+      vm_address_t alloc_start = _hurd_data_end;
+
+      /* We didn't allocate enough space!  Hopefully we can get some more!  */
+
+      if (_hurd_data_end > pagebrk)
+       /* First finish allocation.  */
+       err = __vm_protect (__mach_task_self (), pagebrk,
+                           alloc_start - pagebrk, 0,
+                           VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
+      if (! err)
+       _hurd_brk = alloc_start;
+
+      if (! err)
+       err = __vm_allocate (__mach_task_self (), &alloc_start,
+                            pagend - alloc_start, 0);
+
+      if (! err)
+       _hurd_data_end = pagend;
     }
+  else
+    /* Make the memory accessible.  */
+    err = __vm_protect (__mach_task_self (), pagebrk, pagend - pagebrk,
+                       0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
+
+  if (err)
+    return __hurd_fail (err);
 
   _hurd_brk = addr;
   return 0;
@@ -104,6 +138,8 @@ init_brk (void)
 
   __mutex_init (&_hurd_brk_lock);
 
+  static_data_start = (vm_address_t) (&__data_start ?: &_end);
+
   /* If _hurd_brk is already set, don't change it.  The assumption is that
      it was set in a previous run before something like Emacs's unexec was
      called and dumped all the data up to the break at that point.  */
@@ -112,7 +148,7 @@ init_brk (void)
 
   pagend = round_page (_hurd_brk);
 
-  _hurd_data_end = (vm_address_t) &__data_start + DATA_SIZE;
+  _hurd_data_end = round_page (static_data_start + DATA_SIZE);
 
   if (pagend < _hurd_data_end)
     {