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