* src/vm-limit.c: Do not include sys/resource.h, mem-limits.h does it.
[bpt/emacs.git] / src / vm-limit.c
1 /* Functions for memory limit warnings.
2 Copyright (C) 1990, 1992, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 2008, 2009, 2010 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20 #ifdef emacs
21 #include <config.h>
22 #include <setjmp.h>
23 #include "lisp.h"
24 #endif
25
26 #include "mem-limits.h"
27
28 /*
29 Level number of warnings already issued.
30 0 -- no warnings issued.
31 1 -- 75% warning already issued.
32 2 -- 85% warning already issued.
33 3 -- 95% warning issued; keep warning frequently.
34 */
35 enum warnlevel { not_warned, warned_75, warned_85, warned_95 };
36
37 static enum warnlevel warnlevel;
38
39 /* Function to call to issue a warning;
40 0 means don't issue them. */
41 static void (*warn_function) (const char *);
42
43 /* Start of data space; can be changed by calling malloc_init. */
44 static POINTER data_space_start;
45
46 /* Number of bytes of writable memory we can expect to be able to get. */
47 static unsigned long lim_data;
48 \f
49
50 #if defined (HAVE_GETRLIMIT) && defined (RLIMIT_AS)
51 static void
52 get_lim_data (void)
53 {
54 struct rlimit rlimit;
55
56 getrlimit (RLIMIT_AS, &rlimit);
57 if (rlimit.rlim_cur == RLIM_INFINITY)
58 lim_data = -1;
59 else
60 lim_data = rlimit.rlim_cur;
61 }
62
63 #else /* not HAVE_GETRLIMIT */
64
65 #ifdef USG
66
67 static void
68 get_lim_data (void)
69 {
70 extern long ulimit ();
71
72 lim_data = -1;
73
74 /* Use the ulimit call, if we seem to have it. */
75 #if !defined (ULIMIT_BREAK_VALUE) || defined (GNU_LINUX)
76 lim_data = ulimit (3, 0);
77 #endif
78
79 /* If that didn't work, just use the macro's value. */
80 #ifdef ULIMIT_BREAK_VALUE
81 if (lim_data == -1)
82 lim_data = ULIMIT_BREAK_VALUE;
83 #endif
84
85 lim_data -= (long) data_space_start;
86 }
87
88 #else /* not USG */
89 #ifdef WINDOWSNT
90
91 static void
92 get_lim_data (void)
93 {
94 extern unsigned long reserved_heap_size;
95 lim_data = reserved_heap_size;
96 }
97
98 #else
99 #if !defined (BSD4_2) && !defined (CYGWIN)
100
101 #ifdef MSDOS
102 void
103 get_lim_data (void)
104 {
105 _go32_dpmi_meminfo info;
106 unsigned long lim1, lim2;
107
108 _go32_dpmi_get_free_memory_information (&info);
109 /* DPMI server of Windows NT and its descendants reports in
110 info.available_memory a much lower amount that is really
111 available, which causes bogus "past 95% of memory limit"
112 warnings. Try to overcome that via circumstantial evidence. */
113 lim1 = info.available_memory;
114 lim2 = info.available_physical_pages;
115 /* DPMI Spec: "Fields that are unavailable will hold -1." */
116 if ((long)lim1 == -1L)
117 lim1 = 0;
118 if ((long)lim2 == -1L)
119 lim2 = 0;
120 else
121 lim2 *= 4096;
122 /* Surely, the available memory is at least what we have physically
123 available, right? */
124 if (lim1 >= lim2)
125 lim_data = lim1;
126 else
127 lim_data = lim2;
128 /* Don't believe they will give us more that 0.5 GB. */
129 if (lim_data > 512U * 1024U * 1024U)
130 lim_data = 512U * 1024U * 1024U;
131 }
132
133 unsigned long
134 ret_lim_data (void)
135 {
136 get_lim_data ();
137 return lim_data;
138 }
139 #else /* not MSDOS */
140 static void
141 get_lim_data (void)
142 {
143 lim_data = vlimit (LIM_DATA, -1);
144 }
145 #endif /* not MSDOS */
146
147 #else /* BSD4_2 || CYGWIN */
148
149 static void
150 get_lim_data (void)
151 {
152 struct rlimit XXrlimit;
153
154 getrlimit (RLIMIT_DATA, &XXrlimit);
155 #ifdef RLIM_INFINITY
156 lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */
157 #else
158 lim_data = XXrlimit.rlim_cur; /* soft limit */
159 #endif
160 }
161 #endif /* BSD4_2 */
162 #endif /* not WINDOWSNT */
163 #endif /* not USG */
164 #endif /* not HAVE_GETRLIMIT */
165 \f
166 /* Verify amount of memory available, complaining if we're near the end. */
167
168 static void
169 check_memory_limits (void)
170 {
171 #ifdef REL_ALLOC
172 extern POINTER (*real_morecore) (SIZE);
173 #endif
174 extern POINTER (*__morecore) (SIZE);
175
176 register POINTER cp;
177 unsigned long five_percent;
178 unsigned long data_size;
179 enum warnlevel new_warnlevel;
180
181 if (lim_data == 0)
182 get_lim_data ();
183 five_percent = lim_data / 20;
184
185 /* Find current end of memory and issue warning if getting near max */
186 #ifdef REL_ALLOC
187 if (real_morecore)
188 cp = (char *) (*real_morecore) (0);
189 else
190 #endif
191 cp = (char *) (*__morecore) (0);
192 data_size = (char *) cp - (char *) data_space_start;
193
194 if (!warn_function)
195 return;
196
197 /* What level of warning does current memory usage demand? */
198 new_warnlevel
199 = (data_size > five_percent * 19) ? warned_95
200 : (data_size > five_percent * 17) ? warned_85
201 : (data_size > five_percent * 15) ? warned_75
202 : not_warned;
203
204 /* If we have gone up a level, give the appropriate warning. */
205 if (new_warnlevel > warnlevel || new_warnlevel == warned_95)
206 {
207 warnlevel = new_warnlevel;
208 switch (warnlevel)
209 {
210 case warned_75:
211 (*warn_function) ("Warning: past 75% of memory limit");
212 break;
213
214 case warned_85:
215 (*warn_function) ("Warning: past 85% of memory limit");
216 break;
217
218 case warned_95:
219 (*warn_function) ("Warning: past 95% of memory limit");
220 }
221 }
222 /* Handle going down in usage levels, with some hysteresis. */
223 else
224 {
225 /* If we go down below 70% full, issue another 75% warning
226 when we go up again. */
227 if (data_size < five_percent * 14)
228 warnlevel = not_warned;
229 /* If we go down below 80% full, issue another 85% warning
230 when we go up again. */
231 else if (warnlevel > warned_75 && data_size < five_percent * 16)
232 warnlevel = warned_75;
233 /* If we go down below 90% full, issue another 95% warning
234 when we go up again. */
235 else if (warnlevel > warned_85 && data_size < five_percent * 18)
236 warnlevel = warned_85;
237 }
238
239 if (EXCEEDS_LISP_PTR (cp))
240 (*warn_function) ("Warning: memory in use exceeds lisp pointer size");
241 }
242 \f
243 #if !defined(CANNOT_DUMP) || !defined(SYSTEM_MALLOC)
244 /* Some systems that cannot dump also cannot implement these. */
245
246 /*
247 * Return the address of the start of the data segment prior to
248 * doing an unexec. After unexec the return value is undefined.
249 * See crt0.c for further information and definition of data_start.
250 *
251 * Apparently, on BSD systems this is etext at startup. On
252 * USG systems (swapping) this is highly mmu dependent and
253 * is also dependent on whether or not the program is running
254 * with shared text. Generally there is a (possibly large)
255 * gap between end of text and start of data with shared text.
256 *
257 */
258
259 POINTER
260 start_of_data (void)
261 {
262 #ifdef BSD_SYSTEM
263 extern char etext;
264 return (POINTER)(&etext);
265 #elif defined DATA_START
266 return ((POINTER) DATA_START);
267 #elif defined ORDINARY_LINK
268 /*
269 * This is a hack. Since we're not linking crt0.c or pre_crt0.c,
270 * data_start isn't defined. We take the address of environ, which
271 * is known to live at or near the start of the system crt0.c, and
272 * we don't sweat the handful of bytes that might lose.
273 */
274 extern char **environ;
275 return ((POINTER) &environ);
276 #else
277 extern int data_start;
278 return ((POINTER) &data_start);
279 #endif
280 }
281 #endif /* (not CANNOT_DUMP or not SYSTEM_MALLOC) */
282 \f
283 /* Enable memory usage warnings.
284 START says where the end of pure storage is.
285 WARNFUN specifies the function to call to issue a warning. */
286
287 void
288 memory_warnings (POINTER start, void (*warnfun) (const char *))
289 {
290 extern void (* __after_morecore_hook) (void); /* From gmalloc.c */
291
292 if (start)
293 data_space_start = start;
294 else
295 data_space_start = start_of_data ();
296
297 warn_function = warnfun;
298 __after_morecore_hook = check_memory_limits;
299
300 /* Force data limit to be recalculated on each run. */
301 lim_data = 0;
302 }
303
304 /* arch-tag: eab04eda-1f69-447a-8d9f-95f0a3983ca5
305 (do not change this comment) */