w32heap.c 6.75 KB
Newer Older
Richard M. Stallman's avatar
Richard M. Stallman committed
1 2 3
/* Heap management routines for GNU Emacs on Windows NT.
   Copyright (C) 1994 Free Software Foundation, Inc.

4
This file is part of GNU Emacs.
Richard M. Stallman's avatar
Richard M. Stallman committed
5

6 7 8 9
GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Richard M. Stallman's avatar
Richard M. Stallman committed
10

11 12 13 14
GNU Emacs 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 General Public License for more details.
Richard M. Stallman's avatar
Richard M. Stallman committed
15

16 17 18 19
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Richard M. Stallman's avatar
Richard M. Stallman committed
20 21 22 23

   Geoff Voelker (voelker@cs.washington.edu)			     7-29-94
*/

Geoff Voelker's avatar
Geoff Voelker committed
24 25
#include "config.h"

Richard M. Stallman's avatar
Richard M. Stallman committed
26 27 28 29 30 31 32
#include <stdlib.h>
#include <stdio.h>

#include "ntheap.h"

/* This gives us the page size and the size of the allocation unit on NT.  */
SYSTEM_INFO sysinfo_cache;
Geoff Voelker's avatar
Geoff Voelker committed
33
unsigned long syspage_mask = 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

/* These are defined to get Emacs to compile, but are not used.  */
int edata;
int etext;

/* The major and minor versions of NT.  */
int nt_major_version;
int nt_minor_version;

/* Cache information describing the NT system for later use.  */
void
cache_system_info (void)
{
  union 
    {
      struct info 
	{
	  char  major;
	  char  minor;
	  short platform;
	} info;
      DWORD data;
    } version;

  /* Cache the version of the operating system.  */
  version.data = GetVersion ();
  nt_major_version = version.info.major;
  nt_minor_version = version.info.minor;

  /* Cache page size, allocation unit, processor type, etc.  */
  GetSystemInfo (&sysinfo_cache);
Geoff Voelker's avatar
Geoff Voelker committed
65
  syspage_mask = sysinfo_cache.dwPageSize - 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
}

/* Round ADDRESS up to be aligned with ALIGN.  */
unsigned char *
round_to_next (unsigned char *address, unsigned long align)
{
  unsigned long tmp;

  tmp = (unsigned long) address;
  tmp = (tmp + align - 1) / align;

  return (unsigned char *) (tmp * align);
}

/* Info for keeping track of our heap.  */
unsigned char *data_region_base = NULL;
unsigned char *data_region_end = NULL;
Geoff Voelker's avatar
Geoff Voelker committed
83
unsigned char *real_data_region_end = NULL;
Richard M. Stallman's avatar
Richard M. Stallman committed
84
unsigned long  data_region_size = 0;
85
unsigned long  reserved_heap_size = 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

/* The start of the data segment.  */
unsigned char *
get_data_start (void)
{
  return data_region_base;
}

/* The end of the data segment.  */
unsigned char *
get_data_end (void)
{
  return data_region_end;
}

Geoff Voelker's avatar
Geoff Voelker committed
101
#ifndef WINDOWS95
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
static char *
allocate_heap (void)
{
  unsigned long base = 0x00030000;
  unsigned long end  = 0x00D00000;

  reserved_heap_size = end - base;

  return VirtualAlloc ((void *) base,
		       get_reserved_heap_size (),
		       MEM_RESERVE,
		       PAGE_NOACCESS);
}
#else  
static char *
allocate_heap (void)
{
  unsigned long start     = 0x400000;
Geoff Voelker's avatar
Geoff Voelker committed
120
  unsigned long stop      = 0xD00000;
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
  unsigned long increment = 0x100000;
  char *ptr, *begin = NULL, *end = NULL;
  int i;

  for (i = start; i < stop; i += increment) 
    {
      ptr = VirtualAlloc ((void *) i, increment, MEM_RESERVE, PAGE_NOACCESS);
      if (ptr) 
	begin = begin ? begin : ptr;
      else if (begin)
	{
	  end = ptr;
	  break;
	}
    }

  if (begin && !end)
    end = (char *) i;
  
  if (!begin)
    /* We couldn't allocate any memory for the heap.  Exit.  */
    exit (-2);

  reserved_heap_size = end - begin;
  return begin;
}
#endif


Richard M. Stallman's avatar
Richard M. Stallman committed
150 151 152 153 154 155 156 157 158 159
/* Emulate Unix sbrk.  */
void *
sbrk (unsigned long increment)
{
  void *result;
  long size = (long) increment;
  
  /* Allocate our heap if we haven't done so already.  */
  if (!data_region_base) 
    {
160
      data_region_base = allocate_heap ();
Richard M. Stallman's avatar
Richard M. Stallman committed
161 162 163 164 165 166 167 168 169 170 171 172
      if (!data_region_base)
	return NULL;

      /* Ensure that the addresses don't use the upper 8 bits since
	 the Lisp type goes there (yucko).  */
      if (((unsigned long) data_region_base & 0xFF000000) != 0) 
	{
	  printf ("Error: The heap was allocated in upper memory.\n");
	  exit (1);
	}

      data_region_end = data_region_base;
Geoff Voelker's avatar
Geoff Voelker committed
173
      real_data_region_end = data_region_end;
Richard M. Stallman's avatar
Richard M. Stallman committed
174 175 176 177 178 179 180 181
      data_region_size = get_reserved_heap_size ();
    }
  
  result = data_region_end;
  
  /* If size is negative, shrink the heap by decommitting pages.  */
  if (size < 0) 
    {
Geoff Voelker's avatar
Geoff Voelker committed
182 183 184
      int new_size;
      unsigned char *new_data_region_end;

Richard M. Stallman's avatar
Richard M. Stallman committed
185 186 187 188 189 190
      size = -size;

      /* Sanity checks.  */
      if ((data_region_end - size) < data_region_base)
	return NULL;

Geoff Voelker's avatar
Geoff Voelker committed
191 192 193 194 195 196 197 198 199 200 201 202 203
      /* We can only decommit full pages, so allow for 
	 partial deallocation [cga].  */
      new_data_region_end = (data_region_end - size);
      new_data_region_end = (unsigned char *)
	((long) (new_data_region_end + syspage_mask) & ~syspage_mask);
      new_size = real_data_region_end - new_data_region_end;
      real_data_region_end = new_data_region_end;
      if (new_size > 0) 
	{
	  /* Decommit size bytes from the end of the heap.  */
	  if (!VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
	    return NULL;
 	}
Richard M. Stallman's avatar
Richard M. Stallman committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

      data_region_end -= size;
    } 
  /* If size is positive, grow the heap by committing reserved pages.  */
  else if (size > 0) 
    {
      /* Sanity checks.  */
      if ((data_region_end + size) >
	  (data_region_base + get_reserved_heap_size ()))
	return NULL;

      /* Commit more of our heap. */
      if (VirtualAlloc (data_region_end, size, MEM_COMMIT,
			PAGE_READWRITE) == NULL)
	return NULL;
      data_region_end += size;
Geoff Voelker's avatar
Geoff Voelker committed
220 221 222 223 224

      /* We really only commit full pages, so record where
	 the real end of committed memory is [cga].  */
      real_data_region_end = (unsigned char *)
	  ((long) (data_region_end + syspage_mask) & ~syspage_mask);
Richard M. Stallman's avatar
Richard M. Stallman committed
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
    }
  
  return result;
}

/* Recreate the heap from the data that was dumped to the executable.
   EXECUTABLE_PATH tells us where to find the executable.  */
void
recreate_heap (char *executable_path)
{
  unsigned char *tmp;

  /* First reserve the upper part of our heap.  (We reserve first
     because there have been problems in the past where doing the
     mapping first has loaded DLLs into the VA space of our heap.)  */
  tmp = VirtualAlloc ((void *) get_heap_end (),
		      get_reserved_heap_size () - get_committed_heap_size (),
		      MEM_RESERVE,
		      PAGE_NOACCESS);
  if (!tmp)
    exit (1);

  /* We read in the data for the .bss section from the executable
     first and map in the heap from the executable second to prevent
     any funny interactions between file I/O and file mapping.  */
  read_in_bss (executable_path);
  map_in_heap (executable_path);
}

/* Round the heap up to the given alignment.  */
void
round_heap (unsigned long align)
{
  unsigned long needs_to_be;
  unsigned long need_to_alloc;
  
  needs_to_be = (unsigned long) round_to_next (get_heap_end (), align);
  need_to_alloc = needs_to_be - (unsigned long) get_heap_end ();
  
  if (need_to_alloc) 
    sbrk (need_to_alloc);
}