diff options
Diffstat (limited to 'src/vm-limit.c')
| -rw-r--r-- | src/vm-limit.c | 184 |
1 files changed, 65 insertions, 119 deletions
diff --git a/src/vm-limit.c b/src/vm-limit.c index 2a71e88695a..3fca8bd26c1 100644 --- a/src/vm-limit.c +++ b/src/vm-limit.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* Functions for memory limit warnings. | 1 | /* Functions for memory limit warnings. |
| 2 | Copyright (C) 1990, 1992, 2001-2012 Free Software Foundation, Inc. | 2 | Copyright (C) 1990, 1992, 2001-2013 Free Software Foundation, Inc. |
| 3 | 3 | ||
| 4 | This file is part of GNU Emacs. | 4 | This file is part of GNU Emacs. |
| 5 | 5 | ||
| @@ -19,7 +19,37 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 19 | #include <config.h> | 19 | #include <config.h> |
| 20 | #include <unistd.h> /* for 'environ', on AIX */ | 20 | #include <unistd.h> /* for 'environ', on AIX */ |
| 21 | #include "lisp.h" | 21 | #include "lisp.h" |
| 22 | #include "mem-limits.h" | 22 | |
| 23 | #ifdef MSDOS | ||
| 24 | #include <dpmi.h> | ||
| 25 | extern int etext; | ||
| 26 | #endif | ||
| 27 | |||
| 28 | /* Some systems need this before <sys/resource.h>. */ | ||
| 29 | #include <sys/types.h> | ||
| 30 | |||
| 31 | #ifdef HAVE_SYS_RESOURCE_H | ||
| 32 | # include <sys/time.h> | ||
| 33 | # include <sys/resource.h> | ||
| 34 | #else | ||
| 35 | # if HAVE_SYS_VLIMIT_H | ||
| 36 | # include <sys/vlimit.h> /* Obsolete, says glibc */ | ||
| 37 | # endif | ||
| 38 | #endif | ||
| 39 | |||
| 40 | /* Start of data. It is OK if this is approximate; it's used only as | ||
| 41 | a heuristic. */ | ||
| 42 | #ifdef DATA_START | ||
| 43 | # define data_start ((char *) DATA_START) | ||
| 44 | #else | ||
| 45 | extern char data_start[]; | ||
| 46 | # ifndef HAVE_DATA_START | ||
| 47 | /* Initialize to nonzero, so that it's put into data and not bss. | ||
| 48 | Link this file's object code first, so that this symbol is near the | ||
| 49 | start of data. */ | ||
| 50 | char data_start[1] = { 1 }; | ||
| 51 | # endif | ||
| 52 | #endif | ||
| 23 | 53 | ||
| 24 | /* | 54 | /* |
| 25 | Level number of warnings already issued. | 55 | Level number of warnings already issued. |
| @@ -31,59 +61,45 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 31 | enum warnlevel { not_warned, warned_75, warned_85, warned_95 }; | 61 | enum warnlevel { not_warned, warned_75, warned_85, warned_95 }; |
| 32 | static enum warnlevel warnlevel; | 62 | static enum warnlevel warnlevel; |
| 33 | 63 | ||
| 34 | typedef void *POINTER; | ||
| 35 | |||
| 36 | /* Function to call to issue a warning; | 64 | /* Function to call to issue a warning; |
| 37 | 0 means don't issue them. */ | 65 | 0 means don't issue them. */ |
| 38 | static void (*warn_function) (const char *); | 66 | static void (*warn_function) (const char *); |
| 39 | 67 | ||
| 40 | /* Start of data space; can be changed by calling malloc_init. */ | 68 | /* Start of data space; can be changed by calling memory_warnings. */ |
| 41 | static POINTER data_space_start; | 69 | static char *data_space_start; |
| 42 | 70 | ||
| 43 | /* Number of bytes of writable memory we can expect to be able to get. */ | 71 | /* Number of bytes of writable memory we can expect to be able to get. */ |
| 44 | static size_t lim_data; | 72 | static size_t lim_data; |
| 45 | 73 | ||
| 46 | 74 | /* Return true if PTR cannot be represented as an Emacs Lisp object. */ | |
| 47 | #if defined (HAVE_GETRLIMIT) && defined (RLIMIT_AS) | 75 | static bool |
| 48 | static void | 76 | exceeds_lisp_ptr (void *ptr) |
| 49 | get_lim_data (void) | ||
| 50 | { | 77 | { |
| 51 | struct rlimit rlimit; | 78 | return (! USE_LSB_TAG |
| 52 | 79 | && VAL_MAX < UINTPTR_MAX | |
| 53 | getrlimit (RLIMIT_AS, &rlimit); | 80 | && ((uintptr_t) ptr & ~DATA_SEG_BITS) >> VALBITS != 0); |
| 54 | if (rlimit.rlim_cur == RLIM_INFINITY) | ||
| 55 | lim_data = -1; | ||
| 56 | else | ||
| 57 | lim_data = rlimit.rlim_cur; | ||
| 58 | } | 81 | } |
| 59 | 82 | ||
| 60 | #else /* not HAVE_GETRLIMIT */ | 83 | #ifdef HAVE_GETRLIMIT |
| 61 | 84 | ||
| 62 | #ifdef USG | 85 | # ifndef RLIMIT_AS |
| 86 | # define RLIMIT_AS RLIMIT_DATA | ||
| 87 | # endif | ||
| 63 | 88 | ||
| 64 | static void | 89 | static void |
| 65 | get_lim_data (void) | 90 | get_lim_data (void) |
| 66 | { | 91 | { |
| 67 | extern long ulimit (); | 92 | /* Set LIM_DATA to the minimum of the maximum object size and the |
| 68 | 93 | maximum address space. Don't bother to check for values like | |
| 69 | lim_data = -1; | 94 | RLIM_INFINITY since in practice they are not much less than SIZE_MAX. */ |
| 70 | 95 | struct rlimit rlimit; | |
| 71 | /* Use the ulimit call, if we seem to have it. */ | 96 | lim_data |
| 72 | #if !defined (ULIMIT_BREAK_VALUE) || defined (GNU_LINUX) | 97 | = (getrlimit (RLIMIT_AS, &rlimit) == 0 && rlimit.rlim_cur <= SIZE_MAX |
| 73 | lim_data = ulimit (3, 0); | 98 | ? rlimit.rlim_cur |
| 74 | #endif | 99 | : SIZE_MAX); |
| 75 | |||
| 76 | /* If that didn't work, just use the macro's value. */ | ||
| 77 | #ifdef ULIMIT_BREAK_VALUE | ||
| 78 | if (lim_data == -1) | ||
| 79 | lim_data = ULIMIT_BREAK_VALUE; | ||
| 80 | #endif | ||
| 81 | |||
| 82 | lim_data -= (long) data_space_start; | ||
| 83 | } | 100 | } |
| 84 | 101 | ||
| 85 | #else /* not USG */ | 102 | #elif defined WINDOWSNT |
| 86 | #ifdef WINDOWSNT | ||
| 87 | 103 | ||
| 88 | #include "w32heap.h" | 104 | #include "w32heap.h" |
| 89 | 105 | ||
| @@ -94,10 +110,8 @@ get_lim_data (void) | |||
| 94 | lim_data = reserved_heap_size; | 110 | lim_data = reserved_heap_size; |
| 95 | } | 111 | } |
| 96 | 112 | ||
| 97 | #else | 113 | #elif defined MSDOS |
| 98 | #if !defined (BSD4_2) && !defined (CYGWIN) | ||
| 99 | 114 | ||
| 100 | #ifdef MSDOS | ||
| 101 | void | 115 | void |
| 102 | get_lim_data (void) | 116 | get_lim_data (void) |
| 103 | { | 117 | { |
| @@ -135,32 +149,9 @@ ret_lim_data (void) | |||
| 135 | get_lim_data (); | 149 | get_lim_data (); |
| 136 | return lim_data; | 150 | return lim_data; |
| 137 | } | 151 | } |
| 138 | #else /* not MSDOS */ | ||
| 139 | static void | ||
| 140 | get_lim_data (void) | ||
| 141 | { | ||
| 142 | lim_data = vlimit (LIM_DATA, -1); | ||
| 143 | } | ||
| 144 | #endif /* not MSDOS */ | ||
| 145 | |||
| 146 | #else /* BSD4_2 || CYGWIN */ | ||
| 147 | |||
| 148 | static void | ||
| 149 | get_lim_data (void) | ||
| 150 | { | ||
| 151 | struct rlimit XXrlimit; | ||
| 152 | |||
| 153 | getrlimit (RLIMIT_DATA, &XXrlimit); | ||
| 154 | #ifdef RLIM_INFINITY | ||
| 155 | lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */ | ||
| 156 | #else | 152 | #else |
| 157 | lim_data = XXrlimit.rlim_cur; /* soft limit */ | 153 | # error "get_lim_data not implemented on this machine" |
| 158 | #endif | 154 | #endif |
| 159 | } | ||
| 160 | #endif /* BSD4_2 */ | ||
| 161 | #endif /* not WINDOWSNT */ | ||
| 162 | #endif /* not USG */ | ||
| 163 | #endif /* not HAVE_GETRLIMIT */ | ||
| 164 | 155 | ||
| 165 | /* Verify amount of memory available, complaining if we're near the end. */ | 156 | /* Verify amount of memory available, complaining if we're near the end. */ |
| 166 | 157 | ||
| @@ -168,11 +159,13 @@ static void | |||
| 168 | check_memory_limits (void) | 159 | check_memory_limits (void) |
| 169 | { | 160 | { |
| 170 | #ifdef REL_ALLOC | 161 | #ifdef REL_ALLOC |
| 171 | extern POINTER (*real_morecore) (ptrdiff_t); | 162 | extern void *(*real_morecore) (ptrdiff_t); |
| 163 | #else | ||
| 164 | void *(*real_morecore) (ptrdiff_t) = 0; | ||
| 172 | #endif | 165 | #endif |
| 173 | extern POINTER (*__morecore) (ptrdiff_t); | 166 | extern void *(*__morecore) (ptrdiff_t); |
| 174 | 167 | ||
| 175 | register POINTER cp; | 168 | char *cp; |
| 176 | size_t five_percent; | 169 | size_t five_percent; |
| 177 | size_t data_size; | 170 | size_t data_size; |
| 178 | enum warnlevel new_warnlevel; | 171 | enum warnlevel new_warnlevel; |
| @@ -182,13 +175,8 @@ check_memory_limits (void) | |||
| 182 | five_percent = lim_data / 20; | 175 | five_percent = lim_data / 20; |
| 183 | 176 | ||
| 184 | /* Find current end of memory and issue warning if getting near max */ | 177 | /* Find current end of memory and issue warning if getting near max */ |
| 185 | #ifdef REL_ALLOC | 178 | cp = (real_morecore ? real_morecore : __morecore) (0); |
| 186 | if (real_morecore) | 179 | data_size = cp - data_space_start; |
| 187 | cp = (char *) (*real_morecore) (0); | ||
| 188 | else | ||
| 189 | #endif | ||
| 190 | cp = (char *) (*__morecore) (0); | ||
| 191 | data_size = (char *) cp - (char *) data_space_start; | ||
| 192 | 180 | ||
| 193 | if (!warn_function) | 181 | if (!warn_function) |
| 194 | return; | 182 | return; |
| @@ -235,62 +223,20 @@ check_memory_limits (void) | |||
| 235 | warnlevel = warned_85; | 223 | warnlevel = warned_85; |
| 236 | } | 224 | } |
| 237 | 225 | ||
| 238 | if (EXCEEDS_LISP_PTR (cp)) | 226 | if (exceeds_lisp_ptr (cp)) |
| 239 | (*warn_function) ("Warning: memory in use exceeds lisp pointer size"); | 227 | (*warn_function) ("Warning: memory in use exceeds lisp pointer size"); |
| 240 | } | 228 | } |
| 241 | 229 | ||
| 242 | #if !defined (CANNOT_DUMP) || !defined (SYSTEM_MALLOC) | ||
| 243 | /* Some systems that cannot dump also cannot implement these. */ | ||
| 244 | |||
| 245 | /* | ||
| 246 | * Return the address of the start of the data segment prior to | ||
| 247 | * doing an unexec. After unexec the return value is undefined. | ||
| 248 | * See crt0.c for further information and definition of data_start. | ||
| 249 | * | ||
| 250 | * Apparently, on BSD systems this is etext at startup. On | ||
| 251 | * USG systems (swapping) this is highly mmu dependent and | ||
| 252 | * is also dependent on whether or not the program is running | ||
| 253 | * with shared text. Generally there is a (possibly large) | ||
| 254 | * gap between end of text and start of data with shared text. | ||
| 255 | * | ||
| 256 | */ | ||
| 257 | |||
| 258 | char * | ||
| 259 | start_of_data (void) | ||
| 260 | { | ||
| 261 | #ifdef BSD_SYSTEM | ||
| 262 | extern char etext; | ||
| 263 | return (POINTER)(&etext); | ||
| 264 | #elif defined DATA_START | ||
| 265 | return ((POINTER) DATA_START); | ||
| 266 | #elif defined ORDINARY_LINK | ||
| 267 | /* | ||
| 268 | * This is a hack. Since we're not linking crt0.c or pre_crt0.c, | ||
| 269 | * data_start isn't defined. We take the address of environ, which | ||
| 270 | * is known to live at or near the start of the system crt0.c, and | ||
| 271 | * we don't sweat the handful of bytes that might lose. | ||
| 272 | */ | ||
| 273 | return ((POINTER) &environ); | ||
| 274 | #else | ||
| 275 | extern int data_start; | ||
| 276 | return ((POINTER) &data_start); | ||
| 277 | #endif | ||
| 278 | } | ||
| 279 | #endif /* (not CANNOT_DUMP or not SYSTEM_MALLOC) */ | ||
| 280 | |||
| 281 | /* Enable memory usage warnings. | 230 | /* Enable memory usage warnings. |
| 282 | START says where the end of pure storage is. | 231 | START says where the end of pure storage is. |
| 283 | WARNFUN specifies the function to call to issue a warning. */ | 232 | WARNFUN specifies the function to call to issue a warning. */ |
| 284 | 233 | ||
| 285 | void | 234 | void |
| 286 | memory_warnings (POINTER start, void (*warnfun) (const char *)) | 235 | memory_warnings (void *start, void (*warnfun) (const char *)) |
| 287 | { | 236 | { |
| 288 | extern void (* __after_morecore_hook) (void); /* From gmalloc.c */ | 237 | extern void (* __after_morecore_hook) (void); /* From gmalloc.c */ |
| 289 | 238 | ||
| 290 | if (start) | 239 | data_space_start = start ? start : data_start; |
| 291 | data_space_start = start; | ||
| 292 | else | ||
| 293 | data_space_start = start_of_data (); | ||
| 294 | 240 | ||
| 295 | warn_function = warnfun; | 241 | warn_function = warnfun; |
| 296 | __after_morecore_hook = check_memory_limits; | 242 | __after_morecore_hook = check_memory_limits; |