mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-11-02 09:33:31 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			167 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (C) 1991-2014 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 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
 | 
						|
   Lesser General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU Lesser General Public
 | 
						|
   License along with the GNU C Library; if not, see
 | 
						|
   <http://www.gnu.org/licenses/>.  */
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
#include <hurd.h>
 | 
						|
#include <hurd/resource.h>
 | 
						|
#include <cthreads.h>		/* For `struct mutex'.  */
 | 
						|
 | 
						|
 | 
						|
/* 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.  */
 | 
						|
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 = 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
 | 
						|
__brk (void *inaddr)
 | 
						|
{
 | 
						|
  int ret;
 | 
						|
  HURD_CRITICAL_BEGIN;
 | 
						|
  __mutex_lock (&_hurd_brk_lock);
 | 
						|
  ret = _hurd_set_brk ((vm_address_t) inaddr);
 | 
						|
  __mutex_unlock (&_hurd_brk_lock);
 | 
						|
  HURD_CRITICAL_END;
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
weak_alias (__brk, brk)
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
_hurd_set_brk (vm_address_t addr)
 | 
						|
{
 | 
						|
  error_t err = 0;
 | 
						|
  vm_address_t pagend = round_page (addr);
 | 
						|
  vm_address_t pagebrk = round_page (_hurd_brk);
 | 
						|
  long int rlimit;
 | 
						|
 | 
						|
  if (pagend <= pagebrk)
 | 
						|
    {
 | 
						|
      if (pagend < pagebrk)
 | 
						|
	{
 | 
						|
	  /* 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;
 | 
						|
    }
 | 
						|
 | 
						|
  __mutex_lock (&_hurd_rlimit_lock);
 | 
						|
  rlimit = _hurd_rlimits[RLIMIT_DATA].rlim_cur;
 | 
						|
  __mutex_unlock (&_hurd_rlimit_lock);
 | 
						|
 | 
						|
  if (addr - static_data_start > rlimit)
 | 
						|
    {
 | 
						|
      /* Need to increase the resource limit.  */
 | 
						|
      errno = ENOMEM;
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  if (pagend > _hurd_data_end)
 | 
						|
    {
 | 
						|
      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;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
init_brk (void)
 | 
						|
{
 | 
						|
  vm_address_t pagend;
 | 
						|
 | 
						|
  __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.  */
 | 
						|
  if (_hurd_brk == 0)
 | 
						|
    _hurd_brk = (vm_address_t) &_end;
 | 
						|
 | 
						|
  pagend = round_page (_hurd_brk);
 | 
						|
 | 
						|
  _hurd_data_end = round_page (static_data_start + DATA_SIZE);
 | 
						|
 | 
						|
  if (pagend < _hurd_data_end)
 | 
						|
    {
 | 
						|
      /* We use vm_map to allocate and change permissions atomically.  */
 | 
						|
      if (__vm_map (__mach_task_self (), &pagend, _hurd_data_end - pagend,
 | 
						|
		    0, 0, MACH_PORT_NULL, 0, 0,
 | 
						|
		    0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
 | 
						|
		    VM_INHERIT_COPY))
 | 
						|
	/* Couldn't allocate the memory.  The break will be very short.  */
 | 
						|
	_hurd_data_end = pagend;
 | 
						|
    }
 | 
						|
 | 
						|
  (void) &init_brk;		/* Avoid ``defined but not used'' warning.  */
 | 
						|
}
 | 
						|
text_set_element (_hurd_preinit_hook, init_brk);
 |