ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/win32.c
Revision: 1.2
Committed: Sat Feb 18 15:24:59 2006 UTC (18 years, 2 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: LIBSTATGRAB_0_17, LIBSTATGRAB_0_16, LIBSTATGRAB_0_15, LIBSTATGRAB_0_14, LIBSTATGRAB_0_13, HEAD
Changes since 1.1: +6 -6 lines
Log Message:
Apply fix to Win32 code.

Patch by:	"Tim Teulings" <rael@edge.ping.de>

File Contents

# Content
1 #include "statgrab.h"
2 #ifdef WIN32
3 #include <pdh.h>
4 #include <pdhmsg.h>
5 #include "win32.h"
6 #include <stdio.h>
7 #include "tools.h"
8
9 static HQUERY h_query;
10
11 static HCOUNTER current_han[SG_WIN32_SIZE];
12
13 static char **diskio_names;
14 static HCOUNTER *diskio_rhan;
15 static HCOUNTER *diskio_whan;
16 static int diskio_no;
17
18 static int is_started = 0;
19
20 /*static char **netio_names;
21 static HCOUNTER *netio_rhan;
22 static HCOUNTER *netio_shan;
23 static int netio_no;*/
24
25 int add_counter(const char *fullCounterPath, HCOUNTER *phCounter)
26 {
27 PDH_STATUS pdh_status;
28
29 pdh_status = PdhAddCounter(h_query, fullCounterPath,
30 0, phCounter);
31 if(pdh_status != ERROR_SUCCESS) {
32 //sg_set_error(SG_ERROR_PDHADD, fullCounterPath);
33 phCounter = NULL;
34 return -1;
35 }
36 return 0;
37 }
38
39 int read_counter_double(pdh_enum counter, double *result)
40 {
41 PDH_STATUS pdh_status;
42 PDH_FMT_COUNTERVALUE *item_buf;
43 HCOUNTER hcounter = current_han[counter];
44
45 if(hcounter == NULL)
46 return -1;
47
48 item_buf = sg_malloc(sizeof(PDH_FMT_COUNTERVALUE));
49 if (item_buf == NULL) {
50 return -1;
51 }
52
53 pdh_status = PdhGetFormattedCounterValue(hcounter, PDH_FMT_DOUBLE, NULL,
54 item_buf);
55 if(pdh_status != ERROR_SUCCESS) {
56 free(item_buf);
57 return -1;
58 }
59 *result = item_buf->doubleValue;
60 free(item_buf);
61 return 0;
62 }
63
64 static int read_counter_large_int(HCOUNTER hcounter, long long *result)
65 {
66 PDH_STATUS pdh_status;
67 PDH_FMT_COUNTERVALUE *item_buf;
68
69 if(hcounter == NULL)
70 return -1;
71
72 item_buf = sg_malloc(sizeof(PDH_FMT_COUNTERVALUE));
73 if (item_buf == NULL) {
74 return -1;
75 }
76
77 pdh_status = PdhGetFormattedCounterValue(hcounter, PDH_FMT_LARGE, NULL,
78 item_buf);
79 if(pdh_status != ERROR_SUCCESS) {
80 free(item_buf);
81 /*switch(pdh_status) {
82 case PDH_INVALID_ARGUMENT:
83 printf("invalid argument\n");
84 break;
85 case PDH_INVALID_DATA:
86 printf("invalid data\n");
87 break;
88 case PDH_INVALID_HANDLE:
89 printf("invalid handle\n");
90 break;
91 }*/
92 return -1;
93 }
94 *result = item_buf->largeValue;
95 free(item_buf);
96 return 0;
97 }
98
99 int read_counter_large(pdh_enum counter, long long *result)
100 {
101 return read_counter_large_int(current_han[counter], result);
102 }
103
104 static char *get_instances(const char *object)
105 {
106 PDH_STATUS pdh_status;
107 char *instancelistbuf;
108 DWORD instancelistsize = 0;
109 char *counterlistbuf;
110 DWORD counterlistsize = 0;
111
112 /* Get necessary size of buffers */
113 pdh_status = PdhEnumObjectItems(NULL, NULL, object, NULL,
114 &counterlistsize, NULL, &instancelistsize,
115 PERF_DETAIL_WIZARD, 0);
116 /* 2k is dodgy and returns ERROR_SUCCESS even though the buffers were
117 * NULL */
118 if(pdh_status == PDH_MORE_DATA || pdh_status == ERROR_SUCCESS) {
119 instancelistbuf = sg_malloc(instancelistsize * sizeof(TCHAR));
120 counterlistbuf = sg_malloc(counterlistsize * sizeof(TCHAR));
121 if (instancelistbuf != NULL && counterlistbuf != NULL) {
122 pdh_status = PdhEnumObjectItems(NULL, NULL, object,
123 counterlistbuf, &counterlistsize,
124 instancelistbuf, &instancelistsize,
125 PERF_DETAIL_WIZARD, 0);
126 if (pdh_status == ERROR_SUCCESS) {
127 free(counterlistbuf);
128 return instancelistbuf;
129 }
130 }
131 if (counterlistbuf != NULL)
132 free(counterlistbuf);
133 if(instancelistbuf != NULL)
134 free(instancelistbuf);
135 }
136 return NULL;
137 }
138
139 /* Gets the instance buffer. Removes _Total item. Works out how many items
140 * there are. Returns these in a pointer list, rather than single buffer.
141 */
142 static char **get_instance_list(const char *object, int *n)
143 {
144 char *thisinstance = NULL;
145 char *instances = NULL;
146 char **list;
147 char **listtmp = NULL;
148 int i;
149 *n = 0;
150
151 instances = get_instances(object);
152 if (instances == NULL)
153 return NULL;
154
155 list = (char **)sg_malloc(sizeof(char *));
156 if (list == NULL) {
157 return NULL;
158 }
159 for (thisinstance = instances; *thisinstance != 0;
160 thisinstance += strlen(thisinstance) + 1) {
161 /* Skip over the _Total item */
162 if (strcmp(thisinstance,"_Total") == 0) continue;
163
164 listtmp = (char **)sg_realloc(list, sizeof(char *) * ((*n)+1));
165 if (listtmp == NULL) {
166 goto out;
167 }
168 list = listtmp;
169 list[*n] = sg_malloc(strlen(thisinstance) +1);
170 if(list[*n] == NULL) {
171 goto out;
172 }
173 list[*n] = strcpy(list[*n], thisinstance);
174 ++*n;
175 }
176 free (instances);
177 return list;
178
179 out:
180 for (i = 0; i < *n; i++) {
181 free(list[i]);
182 }
183 free(list);
184 return NULL;
185 }
186
187 char *get_diskio(const int no, long long *read, long long *write)
188 {
189 int result;
190 char *name = NULL;
191
192 if (no >= diskio_no || no < 0)
193 return NULL;
194
195 result = read_counter_large_int(diskio_rhan[no], read);
196 result = result + read_counter_large_int(diskio_whan[no], write);
197 if (result) {
198 sg_set_error(SG_ERROR_PDHREAD, "diskio");
199 return NULL;
200 }
201 if (sg_update_string(&name, diskio_names[no]))
202 return NULL;
203 return name;
204 }
205
206 /* We do not fail on add_counter here, as some counters may not exist on all
207 * hosts. The rest will work, and the missing/failed counters will die nicely
208 * elsewhere */
209 static int add_all_monitors()
210 {
211 int i;
212 char tmp[512];
213
214 add_counter(PDH_USER, &(current_han[SG_WIN32_PROC_USER]));
215 add_counter(PDH_PRIV, &(current_han[SG_WIN32_PROC_PRIV]));
216 add_counter(PDH_IDLE, &(current_han[SG_WIN32_PROC_IDLE]));
217 add_counter(PDH_INTER, &(current_han[SG_WIN32_PROC_INT]));
218 add_counter(PDH_MEM_CACHE, &(current_han[SG_WIN32_MEM_CACHE]));
219 add_counter(PDH_UPTIME, &(current_han[SG_WIN32_UPTIME]));
220 add_counter(PDH_PAGEIN, &(current_han[SG_WIN32_PAGEIN]));
221 add_counter(PDH_PAGEOUT, &(current_han[SG_WIN32_PAGEOUT]));
222
223 diskio_names = get_instance_list("PhysicalDisk", &diskio_no);
224 if (diskio_names != NULL) {
225 diskio_rhan = (HCOUNTER *)malloc(sizeof(HCOUNTER) * diskio_no);
226 if (diskio_rhan == NULL) {
227 PdhCloseQuery(h_query);
228 return -1;
229 }
230 diskio_whan = (HCOUNTER *)malloc(sizeof(HCOUNTER) * diskio_no);
231 if (diskio_whan == NULL) {
232 PdhCloseQuery(h_query);
233 free (diskio_rhan);
234 return -1;
235 }
236 for (i = 0; i < diskio_no; i++) {
237 snprintf(tmp, sizeof(tmp), PDH_DISKIOREAD, diskio_names[i]);
238 add_counter(tmp, &diskio_rhan[i]);
239
240 snprintf(tmp, sizeof(tmp), PDH_DISKIOWRITE, diskio_names[i]);
241 add_counter(tmp, &diskio_whan[i]);
242 }
243 }
244 return 0;
245 }
246 #endif
247
248 /* Call before trying to get search results back, otherwise it'll be dead data
249 */
250 int sg_win32_snapshot()
251 {
252 #ifdef WIN32
253 PDH_STATUS pdh_status;
254
255 if(!is_started) {
256 return -1;
257 }
258
259 pdh_status = PdhCollectQueryData(h_query);
260 if(pdh_status != ERROR_SUCCESS) {
261 sg_set_error(SG_ERROR_PDHCOLLECT, NULL);
262 return -1;
263 }
264 #endif
265 return 0;
266 }
267
268 /* Must be called before any values can be read. This creates all the
269 * necessary PDH values
270 */
271 int sg_win32_start_capture()
272 {
273 #ifdef WIN32
274 PDH_STATUS pdh_status;
275
276 if(is_started) {
277 return -1;
278 }
279
280 pdh_status = PdhOpenQuery(NULL, 0, &h_query);
281
282 if(pdh_status != ERROR_SUCCESS) {
283 char *mess = NULL;
284 if(pdh_status == PDH_INVALID_ARGUMENT)
285 mess = "Invalid argument o.O";
286 else if(pdh_status == PDH_MEMORY_ALLOCATION_FAILURE)
287 mess = "Memory allocation failure";
288 sg_set_error(SG_ERROR_PDHOPEN, mess);
289 return -1;
290 }
291 if (add_all_monitors() == -1) {
292 return -1;
293 }
294
295 is_started = 1;
296 #endif
297 return 0;
298 }
299
300 /* Must be called before the program exits, or to close all the capture items
301 * before opening with a call to start_capture
302 */
303 void sg_win32_end_capture()
304 {
305 #ifdef WIN32
306 int i;
307 PDH_STATUS pdh_status;
308
309 if(!is_started) {
310 return;
311 }
312
313 pdh_status = PdhCloseQuery(h_query);
314 for (i=0; i < SG_WIN32_SIZE; ++i) {
315 PdhRemoveCounter(current_han[i]);
316 current_han[i] = NULL;
317 }
318 /*free_io(&diskio_no, diskio_names, diskio_rhan, diskio_whan);
319 free_io(&netio_no, netio_names, netio_rhan, netio_shan);*/
320 for (i=0; i < diskio_no; ++i) {
321 PdhRemoveCounter(diskio_rhan[i]);
322 PdhRemoveCounter(diskio_whan[i]);
323 free(diskio_names[i]);
324 }
325 free(diskio_names);
326 free(diskio_rhan);
327 free(diskio_whan);
328 diskio_no = 0;
329
330 is_started = 0;
331 #endif
332 }
333