1 /*
2  * app_mem_usage.c
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #if defined(__linux__)
12  #define _XOPEN_SOURCE 500
13 #endif
14 
15 #include "config.h"
16 
17 #include <stdio.h>
18 
19 #include <glib.h>
20 
21 #ifdef _WIN32
22 #include <windows.h>
23 #include <psapi.h>
24 #endif /*  _WIN32 */
25 
26 #if defined(__linux__)
27 # include <sys/types.h>
28 # include <sys/stat.h>
29 # include <unistd.h>
30 # include <fcntl.h>
31 #endif
32 
33 #include "wsutil/file_util.h"
34 #include "app_mem_usage.h"
35 
36 #define MAX_COMPONENTS 16
37 
38 #if defined(_WIN32)
39 
40 static gsize
win32_get_total_mem_used_by_app(void)41 win32_get_total_mem_used_by_app(void)
42 {
43 	HANDLE pHandle;
44 	PROCESS_MEMORY_COUNTERS pmc;
45 	SIZE_T workingSize = 0;
46 
47 	pHandle = GetCurrentProcess();
48 
49 	if (GetProcessMemoryInfo(pHandle, &pmc, sizeof(pmc))){
50 		workingSize = pmc.WorkingSetSize;
51 	}
52 
53 	CloseHandle(pHandle);
54 
55 	if(workingSize == 0){
56 		return -1;
57 	}else{
58 		return (int)workingSize;
59 	}
60 }
61 
62 static const ws_mem_usage_t total_usage = { "Total", win32_get_total_mem_used_by_app, NULL };
63 
64 static const ws_mem_usage_t *memory_components[MAX_COMPONENTS] = {
65 	&total_usage,
66 };
67 
68 static guint memory_register_num = 1;
69 
70 #elif defined(__linux__)
71 
72 static gboolean
linux_get_memory(gsize * ptotal,gsize * prss)73 linux_get_memory(gsize *ptotal, gsize *prss)
74 {
75 	static int fd = -1;
76 	static intptr_t pagesize = 0;
77 
78 	char buf[128];
79 	unsigned long total, rss;
80 	ssize_t ret;
81 
82 	if (!pagesize)
83 		pagesize = sysconf(_SC_PAGESIZE);
84 
85 	if (pagesize == -1)
86 		return FALSE;
87 
88 	if (fd < 0) {
89 		char path[64];
90 
91 		g_snprintf(path, sizeof(path), "/proc/%d/statm", getpid());
92 
93 		fd = ws_open(path, O_RDONLY);
94 
95 		/* XXX, fallback to some other /proc file ? */
96 	}
97 
98 	if (fd < 0)
99 		return FALSE;
100 
101 	ret = pread(fd, buf, sizeof(buf)-1, 0);
102 	if (ret <= 0)
103 		return FALSE;
104 
105 	buf[ret] = '\0';
106 
107 	if (sscanf(buf, "%lu %lu", &total, &rss) != 2)
108 		return FALSE;
109 
110 	if (ptotal)
111 		*ptotal = pagesize * (gsize) total;
112 	if (prss)
113 		*prss = pagesize * (gsize) rss;
114 
115 	return TRUE;
116 }
117 
118 static gsize
linux_get_total_mem_used_by_app(void)119 linux_get_total_mem_used_by_app(void)
120 {
121 	gsize total;
122 
123 	if (!linux_get_memory(&total, NULL))
124 		total = 0;
125 
126 	return total;
127 }
128 
129 static gsize
linux_get_rss_mem_used_by_app(void)130 linux_get_rss_mem_used_by_app(void)
131 {
132 	gsize rss;
133 
134 	if (!linux_get_memory(NULL, &rss))
135 		rss = 0;
136 
137 	return rss;
138 }
139 
140 static const ws_mem_usage_t total_usage = { "Total", linux_get_total_mem_used_by_app, NULL };
141 static const ws_mem_usage_t rss_usage = { "RSS", linux_get_rss_mem_used_by_app, NULL };
142 
143 static const ws_mem_usage_t *memory_components[MAX_COMPONENTS] = {
144 	&total_usage,
145 	&rss_usage,
146 };
147 
148 static guint memory_register_num = 2;
149 
150 #else
151 
152 /*
153  * macOS: task_info()?
154  *
155  * *BSD: getrusage() -> ru_ixrss ?  Note that there are three
156  * current-RSS components in struct rusage, but those date
157  * back to the days when you had just text, data, and stack,
158  * and kernels might not even bother supplying them.
159  */
160 
161 static const ws_mem_usage_t *memory_components[MAX_COMPONENTS];
162 
163 static guint memory_register_num = 0;
164 
165 #endif
166 
167 /* public API */
168 
169 void
memory_usage_component_register(const ws_mem_usage_t * component)170 memory_usage_component_register(const ws_mem_usage_t *component)
171 {
172 	if (memory_register_num >= MAX_COMPONENTS)
173 		return;
174 
175 	memory_components[memory_register_num++] = component;
176 }
177 
178 const char *
memory_usage_get(guint idx,gsize * value)179 memory_usage_get(guint idx, gsize *value)
180 {
181 	if (idx >= memory_register_num)
182 		return NULL;
183 
184 	if (value)
185 		*value = memory_components[idx]->fetch();
186 
187 	return memory_components[idx]->name;
188 }
189 
190 void
memory_usage_gc(void)191 memory_usage_gc(void)
192 {
193 	guint i;
194 
195 	for (i = 0; i < memory_register_num; i++) {
196 		if (memory_components[i]->gc)
197 			memory_components[i]->gc();
198 	}
199 }
200 
201 
202 /*
203  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
204  *
205  * Local variables:
206  * c-basic-offset: 8
207  * tab-width: 8
208  * indent-tabs-mode: t
209  * End:
210  *
211  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
212  * :indentSize=8:tabSize=8:noTabs=false:
213  */
214