1 //
2 //	aegis - project change supervisor
3 //	Copyright (C) 2005-2008 Peter Miller
4 //
5 //	This program is free software; you can redistribute it and/or modify
6 //	it under the terms of the GNU General Public License as published by
7 //	the Free Software Foundation; either version 3 of the License, or
8 //	(at your option) any later version.
9 //
10 //	This program is distributed in the hope that it will be useful,
11 //	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //	GNU General Public License for more details.
14 //
15 //	You should have received a copy of the GNU General Public License
16 //	along with this program. If not, see
17 //	<http://www.gnu.org/licenses/>.
18 //
19 
20 #include <common/ac/signal.h>
21 #include <common/ac/stdio.h>
22 #include <common/ac/unistd.h>
23 #include <common/ac/sys/resource.h>
24 
25 #include <common/rsrc_limits.h>
26 
27 
28 //
29 // This is a disgusting hack to get around a disgusting hack in glibc's
30 // implementation of sys/resource.h
31 //
32 // Glibc introduces a typedef for the first argument of getrlimit, and in
33 // some versions, fails to insulate this against C++ which has stricter
34 // enum to int rules than C does.  This results in a compile time error.
35 //
36 #ifndef __USE_GNU
37 typedef int rlimit_resource_ty;
38 #else
39 typedef __rlimit_resource_t rlimit_resource_ty;
40 #endif
41 
42 
43 static void
adjust_resource(rlimit_resource_ty resource)44 adjust_resource(rlimit_resource_ty resource)
45 {
46     rlimit r;
47     if (getrlimit(resource, &r) >= 0 && r.rlim_cur != r.rlim_max)
48     {
49 	r.rlim_cur = r.rlim_max;
50 	setrlimit(resource, &r);
51     }
52 }
53 
54 
55 void
resource_limits_init()56 resource_limits_init()
57 {
58     //
59     // From getrlimit(2) manual page:  "A child process created via
60     // fork(2) inherits its parents resource limits.  Resource
61     // limits are preserved across execve(2)."
62     //
63     adjust_resource(RLIMIT_AS);
64     adjust_resource(RLIMIT_DATA);
65     adjust_resource(RLIMIT_FSIZE);
66 
67     //
68     // Some operating systems generate the SIGXFSZ signal when a
69     // file exceeds the getrlimit(RLIMIT_FSIZE) size, in addition to
70     // returning the EFBIG errno value.  By ignoring this signal, the
71     // error gets returned and it is possible to report the offending
72     // file's name, making for a more useful error message.
73     //
74     // Linux ignores this signal by default, but allows it to be
75     // set.  Other posix implementations may not ignore this signal by
76     // default.
77     //
78 #ifdef SIGXFSZ
79     signal(SIGXFSZ, SIG_IGN);
80 #endif
81 }
82 
83 
84 #ifdef __linux__
85 
86 
87 static void
print_size(long size,const char * caption,int pagesize)88 print_size(long size, const char *caption, int pagesize)
89 {
90     if (pagesize <= 1 || size == 0)
91     {
92 	fprintf(stderr, "%8ld   %s\n", size, caption);
93 	return;
94     }
95 
96     while (pagesize < 1024)
97     {
98 	size = (size + 1) >> 1;
99 	pagesize <<= 1;
100     }
101     pagesize >>= 10;
102 
103     size *= pagesize;
104     if (size < 10000)
105     {
106 	fprintf(stderr, "%4ldk  %s\n", size, caption);
107 	return;
108     }
109     size = (size + 512) >> 10;
110     if (size < 10000)
111     {
112 	fprintf(stderr, "%4ldM  %s\n", size, caption);
113 	return;
114     }
115     size = (size + 512) >> 10;
116     fprintf(stderr, "%4ldG  %s\n", size, caption);
117 }
118 
119 #endif // __linux__
120 
121 
122 void
resource_usage_print()123 resource_usage_print()
124 {
125 #ifdef __linux__
126     const char *fn = "/proc/self/statm";
127     FILE *fp = fopen(fn, "r");
128     if (!fp)
129 	return;
130     long size, resident, share, trs, drs, lrs;
131     fscanf(fp, "%ld%ld%ld%ld%ld%ld",
132 	&size, &resident, &share, &trs, &drs, &lrs);
133     fclose(fp);
134 
135     long pagesize = getpagesize();
136 
137     print_size(size, "total program size", pagesize);
138     print_size(resident, "resident set size", pagesize);
139     print_size(share, "shared pages", pagesize);
140     print_size(trs, "text (code)", pagesize);
141     print_size(drs, "data/stack", pagesize);
142     print_size(lrs, "library", pagesize);
143 #endif // __linux__
144 }
145