Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: src/lib/util/memlimit.c

Issue 2847081: Initial code. (Closed) Base URL: ssh://git@chromiumos-git/libscrypt.git
Patch Set: Use scrypt distro and patch with changes instead. Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/lib/util/memlimit.h ('k') | src/lib/util/readpass.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*-
2 * Copyright 2009 Colin Percival
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * This file was originally written by Colin Percival as part of the Tarsnap
27 * online backup system.
28 */
29 #include "scrypt_platform.h"
30
31 #include <sys/types.h>
32 #include <sys/resource.h>
33
34 #ifdef HAVE_SYS_PARAM_H
35 #include <sys/param.h>
36 #endif
37 #ifdef HAVE_SYSCTL_HW_USERMEM
38 #include <sys/sysctl.h>
39 #endif
40 #ifdef HAVE_SYS_SYSINFO_H
41 #include <sys/sysinfo.h>
42 #endif
43
44 #include <errno.h>
45 #include <stddef.h>
46 #include <stdint.h>
47 #include <unistd.h>
48
49 #ifdef DEBUG
50 #include <stdio.h>
51 #endif
52
53 #include "memlimit.h"
54
55 #ifdef HAVE_SYSCTL_HW_USERMEM
56 static int
57 memlimit_sysctl_hw_usermem(size_t * memlimit)
58 {
59 int mib[2];
60 uint8_t usermembuf[8];
61 size_t usermemlen = 8;
62 uint64_t usermem;
63
64 /* Ask the kernel how much RAM we have. */
65 mib[0] = CTL_HW;
66 mib[1] = HW_USERMEM;
67 if (sysctl(mib, 2, usermembuf, &usermemlen, NULL, 0))
68 return (1);
69
70 /*
71 * Parse as either a uint64_t or a uint32_t based on the length of
72 * output the kernel reports having copied out. It appears that all
73 * systems providing a sysctl interface for reading integers copy
74 * them out as system-endian values, so we don't need to worry about
75 * parsing them.
76 */
77 if (usermemlen == sizeof(uint64_t))
78 usermem = *(uint64_t *)usermembuf;
79 else if (usermemlen == sizeof(uint32_t))
80 usermem = *(uint32_t *)usermembuf;
81 else
82 return (1);
83
84 /* Return the sysctl value, but clamp to SIZE_MAX if necessary. */
85 #if UINT64_MAX > SIZE_MAX
86 if (usermem > SIZE_MAX)
87 *memlimit = SIZE_MAX;
88 else
89 *memlimit = usermem;
90 #else
91 *memlimit = usermem;
92 #endif
93
94 /* Success! */
95 return (0);
96 }
97 #endif
98
99 /* If we don't HAVE_STRUCT_SYSINFO, we can't use sysinfo. */
100 #ifndef HAVE_STRUCT_SYSINFO
101 #undef HAVE_SYSINFO
102 #endif
103
104 /* If we don't HAVE_STRUCT_SYSINFO_TOTALRAM, we can't use sysinfo. */
105 #ifndef HAVE_STRUCT_SYSINFO_TOTALRAM
106 #undef HAVE_SYSINFO
107 #endif
108
109 #ifdef HAVE_SYSINFO
110 static int
111 memlimit_sysinfo(size_t * memlimit)
112 {
113 struct sysinfo info;
114 uint64_t totalmem;
115
116 /* Get information from the kernel. */
117 if (sysinfo(&info))
118 return (1);
119 totalmem = info.totalram;
120
121 /* If we're on a modern kernel, adjust based on mem_unit. */
122 #ifdef HAVE_STRUCT_SYSINFO_MEM_UNIT
123 totalmem = totalmem * info.mem_unit;
124 #endif
125
126 /* Return the value, but clamp to SIZE_MAX if necessary. */
127 #if UINT64_MAX > SIZE_MAX
128 if (totalmem > SIZE_MAX)
129 *memlimit = SIZE_MAX;
130 else
131 *memlimit = totalmem;
132 #else
133 *memlimit = totalmem;
134 #endif
135
136 /* Success! */
137 return (0);
138 }
139 #endif /* HAVE_SYSINFO */
140
141 static int
142 memlimit_rlimit(size_t * memlimit)
143 {
144 struct rlimit rl;
145 uint64_t memrlimit;
146
147 /* Find the least of... */
148 memrlimit = (uint64_t)(-1);
149
150 /* ... RLIMIT_AS... */
151 #ifdef RLIMIT_AS
152 if (getrlimit(RLIMIT_AS, &rl))
153 return (1);
154 if ((rl.rlim_cur != RLIM_INFINITY) &&
155 ((uint64_t)rl.rlim_cur < memrlimit))
156 memrlimit = rl.rlim_cur;
157 #endif
158
159 /* ... RLIMIT_DATA... */
160 if (getrlimit(RLIMIT_DATA, &rl))
161 return (1);
162 if ((rl.rlim_cur != RLIM_INFINITY) &&
163 ((uint64_t)rl.rlim_cur < memrlimit))
164 memrlimit = rl.rlim_cur;
165
166 /* ... and RLIMIT_RSS. */
167 #ifdef RLIMIT_RSS
168 if (getrlimit(RLIMIT_RSS, &rl))
169 return (1);
170 if ((rl.rlim_cur != RLIM_INFINITY) &&
171 ((uint64_t)rl.rlim_cur < memrlimit))
172 memrlimit = rl.rlim_cur;
173 #endif
174
175 /* Return the value, but clamp to SIZE_MAX if necessary. */
176 #if UINT64_MAX > SIZE_MAX
177 if (memrlimit > SIZE_MAX)
178 *memlimit = SIZE_MAX;
179 else
180 *memlimit = memrlimit;
181 #else
182 *memlimit = memrlimit;
183 #endif
184
185 /* Success! */
186 return (0);
187 }
188
189 #ifdef _SC_PHYS_PAGES
190
191 /* Some systems define _SC_PAGESIZE instead of _SC_PAGE_SIZE. */
192 #ifndef _SC_PAGE_SIZE
193 #define _SC_PAGE_SIZE _SC_PAGESIZE
194 #endif
195
196 static int
197 memlimit_sysconf(size_t * memlimit)
198 {
199 long pagesize;
200 long physpages;
201 uint64_t totalmem;
202
203 /* Set errno to 0 in order to distinguish "no limit" from "error". */
204 errno = 0;
205
206 /* Read the two limits. */
207 if (((pagesize = sysconf(_SC_PAGE_SIZE)) == -1) ||
208 ((physpages = sysconf(_SC_PHYS_PAGES)) == -1)) {
209 /* Did an error occur? */
210 if (errno != 0)
211 return (1);
212
213 /* If not, there is no limit. */
214 totalmem = (uint64_t)(-1);
215 } else {
216 /* Compute the limit. */
217 totalmem = (uint64_t)(pagesize) * (uint64_t)(physpages);
218 }
219
220 /* Return the value, but clamp to SIZE_MAX if necessary. */
221 #if UINT64_MAX > SIZE_MAX
222 if (totalmem > SIZE_MAX)
223 *memlimit = SIZE_MAX;
224 else
225 *memlimit = totalmem;
226 #else
227 *memlimit = totalmem;
228 #endif
229
230 /* Success! */
231 return (0);
232 }
233 #endif
234
235 int
236 memtouse(size_t maxmem, double maxmemfrac, size_t * memlimit)
237 {
238 size_t sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit;
239 size_t sysconf_memlimit;
240 size_t memlimit_min;
241 size_t memavail;
242
243 /* Get memory limits. */
244 #ifdef HAVE_SYSCTL_HW_USERMEM
245 if (memlimit_sysctl_hw_usermem(&sysctl_memlimit))
246 return (1);
247 #else
248 sysctl_memlimit = (size_t)(-1);
249 #endif
250 #ifdef HAVE_SYSINFO
251 if (memlimit_sysinfo(&sysinfo_memlimit))
252 return (1);
253 #else
254 sysinfo_memlimit = (size_t)(-1);
255 #endif
256 if (memlimit_rlimit(&rlimit_memlimit))
257 return (1);
258 #ifdef _SC_PHYS_PAGES
259 if (memlimit_sysconf(&sysconf_memlimit))
260 return (1);
261 #else
262 sysconf_memlimit = (size_t)(-1);
263 #endif
264
265 #ifdef DEBUG
266 fprintf(stderr, "Memory limits are %zu %zu %zu %zu\n",
267 sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit,
268 sysconf_memlimit);
269 #endif
270
271 /* Find the smallest of them. */
272 memlimit_min = (size_t)(-1);
273 if (memlimit_min > sysctl_memlimit)
274 memlimit_min = sysctl_memlimit;
275 if (memlimit_min > sysinfo_memlimit)
276 memlimit_min = sysinfo_memlimit;
277 if (memlimit_min > rlimit_memlimit)
278 memlimit_min = rlimit_memlimit;
279 if (memlimit_min > sysconf_memlimit)
280 memlimit_min = sysconf_memlimit;
281
282 /* Only use the specified fraction of the available memory. */
283 if ((maxmemfrac > 0.5) || (maxmemfrac == 0.0))
284 maxmemfrac = 0.5;
285 memavail = maxmemfrac * memlimit_min;
286
287 /* Don't use more than the specified maximum. */
288 if ((maxmem > 0) && (memavail > maxmem))
289 memavail = maxmem;
290
291 /* But always allow at least 1 MiB. */
292 if (memavail < 1048576)
293 memavail = 1048576;
294
295 #ifdef DEBUG
296 fprintf(stderr, "Allowing up to %zu memory to be used\n", memavail);
297 #endif
298
299 /* Return limit via the provided pointer. */
300 *memlimit = memavail;
301 return (0);
302 }
OLDNEW
« no previous file with comments | « src/lib/util/memlimit.h ('k') | src/lib/util/readpass.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698