mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-30 10:45:40 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			167 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright (C) 1991-2016 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);
 |