1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/types.h>
29 #include <sys/resource.h>
30 #include <sys/loadavg.h>
31 #include <sys/time.h>
32 #include <sys/stat.h>
33 #include <sys/utsname.h>
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <dirent.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <poll.h>
42 #include <ctype.h>
43 #include <fcntl.h>
44 #include <limits.h>
45 #include <time.h>
46 #include <project.h>
47 #include <libintl.h>
48 #include <pthread.h>
49
50 #include "rdimpl.h"
51 #include "rdutil.h"
52 #include "rdtable.h"
53 #include "rdfile.h"
54 #include "rdlist.h"
55
56 /* global variables */
57
58 extern pthread_mutex_t listLock;
59
60 list_t lwps; /* list of lwps/processes */
61 list_t users; /* list of users */
62 list_t projects; /* list of projects */
63 list_t processes; /* list of processes */
64
65 sys_info_t sys_info;
66
67 jmp_buf dm_jmpbuffer;
68 char errmsg[NL_TEXTMAX]; /* error message max 255 */
69
70 static float total_mem; /* total memory usage */
71 static float total_cpu; /* total cpu usage */
72 static char *nullstr = "null";
73 static double loadavg[3];
74 static DIR *procdir;
75
76
77 /*
78 * Add a LWP entry to the specifed list.
79 */
80 lwp_info_t *
list_add_lwp(list_t * list,pid_t pid,id_t lwpid)81 list_add_lwp(list_t *list, pid_t pid, id_t lwpid)
82 {
83 lwp_info_t *lwp;
84
85 if (list->l_head == NULL) {
86 list->l_head = list->l_tail = lwp = Zalloc(sizeof (lwp_info_t));
87 } else {
88 lwp = Zalloc(sizeof (lwp_info_t));
89 lwp->li_prev = list->l_tail;
90 ((lwp_info_t *)list->l_tail)->li_next = lwp;
91 list->l_tail = lwp;
92 }
93 lwp->li_lwpsinfo = Zalloc(sizeof (lwpsinfo_t));
94 lwp->li_psinfo = Zalloc(sizeof (psinfo_t));
95 lwp->li_psinfo->pr_pid = pid;
96 lwp->li_lwpsinfo->pr_lwpid = lwpid;
97 lwpid_add(lwp, pid, lwpid);
98 list->l_count++;
99 return (lwp);
100 }
101
102
103 /*
104 * Remove an LWP entry from the specified list.
105 */
106 static void
list_remove_lwp(list_t * list,lwp_info_t * lwp)107 list_remove_lwp(list_t *list, lwp_info_t *lwp)
108 {
109
110 if (lwp->li_prev)
111 lwp->li_prev->li_next = lwp->li_next;
112 else
113 list->l_head = lwp->li_next; /* removing the head */
114 if (lwp->li_next)
115 lwp->li_next->li_prev = lwp->li_prev;
116 else
117 list->l_tail = lwp->li_prev; /* removing the tail */
118 lwpid_del(lwp->li_psinfo->pr_pid, lwp->li_lwpsinfo->pr_lwpid);
119 if (lwpid_pidcheck(lwp->li_psinfo->pr_pid) == 0)
120 fds_rm(lwp->li_psinfo->pr_pid);
121 list->l_count--;
122 Free(lwp->li_lwpsinfo);
123 Free(lwp->li_psinfo);
124 Free(lwp);
125 }
126
127
128 /*
129 * Remove entry from the specified list.
130 */
131 static void
list_remove_id(list_t * list,id_info_t * id)132 list_remove_id(list_t *list, id_info_t *id)
133 {
134
135 if (id->id_prev)
136 id->id_prev->id_next = id->id_next;
137 else
138 list->l_head = id->id_next; /* removing the head */
139 if (id->id_next)
140 id->id_next->id_prev = id->id_prev;
141 else
142 list->l_tail = id->id_prev; /* removing the tail */
143
144 list->l_count--;
145 /* anly free if doesn't point to static 'nullstr' def */
146 if (id->id_name != nullstr)
147 Free(id->id_name);
148 Free(id);
149 }
150
151
152 /*
153 * Empty the specified list.
154 * If it's an LWP list, this will traverse /proc to
155 * restore microstate accounting to its original value.
156 */
157 void
list_clear(list_t * list)158 list_clear(list_t *list)
159 {
160 if (list->l_type == LT_LWPS) {
161 lwp_info_t *lwp = list->l_tail;
162 lwp_info_t *lwp_tmp;
163
164 fd_closeall();
165 while (lwp) {
166 lwp_tmp = lwp;
167 lwp = lwp->li_prev;
168 list_remove_lwp(&lwps, lwp_tmp);
169 }
170 } else {
171 id_info_t *id = list->l_head;
172 id_info_t *nextid;
173 while (id) {
174 nextid = id->id_next;
175 /* anly free if doesn't point to static 'nullstr' def */
176 if (id->id_name != nullstr)
177 Free(id->id_name);
178 Free(id);
179 id = nextid;
180 }
181 list->l_count = 0;
182 list->l_head = list->l_tail = NULL;
183 }
184 }
185
186
187 /*
188 * Calculate a process' statistics from its lwp statistics.
189 */
190 static void
id_update(id_info_t * id,lwp_info_t * lwp,int l_type)191 id_update(id_info_t *id, lwp_info_t *lwp, int l_type) {
192 char usrname[LOGNAME_MAX+1];
193 char projname[PROJNAME_MAX+1];
194
195 /*
196 * When an id is processed first time in an update run its
197 * id_alive flag set to false.
198 * The next values are gauges, their old values from the previous
199 * calculation should be set to null.
200 * The names and timestamp must be set once.
201 */
202 if (id->id_alive == B_FALSE) {
203 id->id_hpsize = 0;
204 id->id_size = 0;
205 id->id_rssize = 0;
206 id->id_pctmem = 0;
207 id->id_timestamp = 0;
208 id->id_time = 0;
209 id->id_pctcpu = 0;
210 id->id_nlwps = 0;
211 id->id_nproc = 0;
212 id->id_pid = (int)-1;
213 id->id_taskid = lwp->li_psinfo->pr_taskid;
214 id->id_projid = lwp->li_psinfo->pr_projid;
215 id->id_psetid = lwp->li_lwpsinfo->pr_bindpset;
216 id->id_uid = lwp->li_psinfo->pr_uid;
217 if (l_type == LT_USERS) {
218 getusrname(id->id_uid, usrname, LOGNAME_MAX+1);
219 id->id_name = Realloc(id->id_name,
220 strlen(usrname) + 1);
221 (void) strcpy(id->id_name, usrname);
222 } else if (l_type == LT_PROJECTS) {
223 getprojname(id->id_projid, projname, PROJNAME_MAX);
224 id->id_name = Realloc(id->id_name,
225 strlen(projname) + 1);
226 (void) strcpy(id->id_name, projname);
227 } else {
228 id->id_name = nullstr;
229 }
230 id->id_timestamp = get_timestamp();
231 /* mark this id as changed in this update run */
232 id->id_alive = B_TRUE;
233 }
234
235 if (lwp->li_psinfo->pr_nlwp > 0) {
236 id->id_nlwps++;
237 }
238
239 /*
240 * The next values are calculated only one time for each pid.
241 */
242 if ((id->id_pid != lwp->li_psinfo->pr_pid) &&
243 (lwp->rlwpid == lwp->li_lwpsinfo->pr_lwpid)) {
244 id->id_nproc++;
245 id->id_hpsize += (lwp->li_hpsize/1024);
246 id->id_size += lwp->li_psinfo->pr_size;
247 id->id_rssize += lwp->li_psinfo->pr_rssize;
248 id->id_pctmem += FRC2PCT(lwp->li_psinfo->pr_pctmem);
249 id->id_pid = lwp->li_psinfo->pr_pid;
250 if (l_type == LT_PROCESS)
251 total_mem += FRC2PCT(lwp->li_psinfo->pr_pctmem);
252 }
253
254 id->id_pctcpu += FRC2PCT(lwp->li_lwpsinfo->pr_pctcpu);
255 if (l_type == LT_PROCESS)
256 total_cpu += FRC2PCT(lwp->li_lwpsinfo->pr_pctcpu);
257 id->id_time += TIME2SEC(lwp->li_lwpsinfo->pr_time);
258 id->id_usr += lwp->li_usr;
259 id->id_sys += lwp->li_sys;
260 id->id_ttime += lwp->li_ttime;
261 id->id_tpftime += lwp->li_tpftime;
262 id->id_dpftime += lwp->li_dpftime;
263 id->id_kpftime += lwp->li_kpftime;
264 id->id_lck += lwp->li_lck;
265 id->id_slp += lwp->li_slp;
266 id->id_lat += lwp->li_lat;
267 id->id_stime += lwp->li_stime;
268 id->id_minf += lwp->li_minf;
269 id->id_majf += lwp->li_majf;
270 id->id_nswap += lwp->li_nswap;
271 id->id_inblk += lwp->li_inblk;
272 id->id_oublk += lwp->li_oublk;
273 id->id_msnd += lwp->li_msnd;
274 id->id_mrcv += lwp->li_mrcv;
275 id->id_sigs += lwp->li_sigs;
276 id->id_vctx += lwp->li_vctx;
277 id->id_ictx += lwp->li_ictx;
278 id->id_scl += lwp->li_scl;
279 id->id_ioch += lwp->li_ioch;
280 }
281
282 static void
list_update(list_t * list,lwp_info_t * lwp)283 list_update(list_t *list, lwp_info_t *lwp)
284 {
285 id_info_t *id;
286 if (list->l_head == NULL) { /* first element */
287 list->l_head = list->l_tail = id = Zalloc(sizeof (id_info_t));
288 id_update(id, lwp, list->l_type);
289 list->l_count++;
290 return;
291 }
292
293 for (id = list->l_head; id; id = id->id_next) {
294 if ((list->l_type == LT_PROCESS) &&
295 (id->id_pid != lwp->li_psinfo->pr_pid))
296 continue;
297 if ((list->l_type == LT_USERS) &&
298 (id->id_uid != lwp->li_psinfo->pr_uid))
299 continue;
300 if ((list->l_type == LT_PROJECTS) &&
301 (id->id_projid != lwp->li_psinfo->pr_projid))
302 continue;
303 id_update(id, lwp, list->l_type);
304 return;
305 }
306
307 /* a new element */
308 id = list->l_tail;
309 id->id_next = Zalloc(sizeof (id_info_t));
310 id->id_next->id_prev = list->l_tail;
311 id->id_next->id_next = NULL;
312 list->l_tail = id->id_next;
313 id = list->l_tail;
314 id_update(id, lwp, list->l_type);
315 list->l_count++;
316 }
317
318 /*
319 * This procedure removes all dead procs/user/.. from the specified list.
320 */
321 static void
list_refresh_id(list_t * list)322 list_refresh_id(list_t *list)
323 {
324 id_info_t *id, *id_next;
325
326 if (!(list->l_type & LT_PROCESS) && !(list->l_type & LT_USERS) &&
327 !(list->l_type & LT_TASKS) && !(list->l_type & LT_PROJECTS) &&
328 !(list->l_type & LT_PSETS)) {
329 return;
330 }
331 id = list->l_head;
332
333 while (id) {
334 if (id->id_alive == B_FALSE) { /* id is dead */
335 id_next = id->id_next;
336 list_remove_id(list, id);
337 id = id_next;
338 } else {
339
340 /* normalize total mem and cpu across all processes. */
341 if (total_mem >= 100)
342 id->id_pctmem = (100 * id->id_pctmem) /
343 total_mem;
344 if (total_cpu >= 100)
345 id->id_pctcpu = (100 * id->id_pctcpu) /
346 total_cpu;
347
348 id->id_alive = B_FALSE;
349 id = id->id_next;
350 }
351 }
352 }
353
354 /*
355 * This procedure removes all dead lwps from the specified lwp list.
356 */
357 static void
list_refresh(list_t * list)358 list_refresh(list_t *list)
359 {
360 lwp_info_t *lwp, *lwp_next;
361
362 if (!(list->l_type & LT_LWPS))
363 return;
364 lwp = list->l_head;
365
366 while (lwp) {
367 if (lwp->li_alive == B_FALSE) { /* lwp is dead */
368 lwp_next = lwp->li_next;
369 list_remove_lwp(&lwps, lwp);
370 lwp = lwp_next;
371 } else {
372 lwp->li_alive = B_FALSE;
373 lwp = lwp->li_next;
374 }
375 }
376 }
377
378
379 /*
380 * Update a LWP entry according to the specified usage data.
381 */
382 static void
lwp_update(lwp_info_t * lwp,struct prusage * usage_buf)383 lwp_update(lwp_info_t *lwp, struct prusage *usage_buf)
384 {
385 lwp->li_usr = (double)(TIME2NSEC(usage_buf->pr_utime) -
386 TIME2NSEC(lwp->li_usage.pr_utime)) / NANOSEC;
387 lwp->li_sys = (double)(TIME2NSEC(usage_buf->pr_stime) -
388 TIME2NSEC(lwp->li_usage.pr_stime)) / NANOSEC;
389 lwp->li_ttime = (double)(TIME2NSEC(usage_buf->pr_ttime) -
390 TIME2NSEC(lwp->li_usage.pr_ttime)) / NANOSEC;
391 lwp->li_tpftime = (double)(TIME2NSEC(usage_buf->pr_tftime) -
392 TIME2NSEC(lwp->li_usage.pr_tftime)) / NANOSEC;
393 lwp->li_dpftime = (double)(TIME2NSEC(usage_buf->pr_dftime) -
394 TIME2NSEC(lwp->li_usage.pr_dftime)) / NANOSEC;
395 lwp->li_kpftime = (double)(TIME2NSEC(usage_buf->pr_kftime) -
396 TIME2NSEC(lwp->li_usage.pr_kftime)) / NANOSEC;
397 lwp->li_lck = (double)(TIME2NSEC(usage_buf->pr_ltime) -
398 TIME2NSEC(lwp->li_usage.pr_ltime)) / NANOSEC;
399 lwp->li_slp = (double)(TIME2NSEC(usage_buf->pr_slptime) -
400 TIME2NSEC(lwp->li_usage.pr_slptime)) / NANOSEC;
401 lwp->li_lat = (double)(TIME2NSEC(usage_buf->pr_wtime) -
402 TIME2NSEC(lwp->li_usage.pr_wtime)) / NANOSEC;
403 lwp->li_stime = (double)(TIME2NSEC(usage_buf->pr_stoptime) -
404 TIME2NSEC(lwp->li_usage.pr_stoptime)) / NANOSEC;
405 lwp->li_minf = usage_buf->pr_minf - lwp->li_usage.pr_minf;
406 lwp->li_majf = usage_buf->pr_majf - lwp->li_usage.pr_majf;
407 lwp->li_nswap = usage_buf->pr_nswap - lwp->li_usage.pr_nswap;
408 lwp->li_inblk = usage_buf->pr_inblk - lwp->li_usage.pr_inblk;
409 lwp->li_oublk = usage_buf->pr_oublk -lwp->li_usage.pr_oublk;
410 lwp->li_msnd = usage_buf->pr_msnd - lwp->li_usage.pr_msnd;
411 lwp->li_mrcv = usage_buf->pr_mrcv - lwp->li_usage.pr_mrcv;
412 lwp->li_sigs = usage_buf->pr_sigs - lwp->li_usage.pr_sigs;
413 lwp->li_vctx = usage_buf->pr_vctx - lwp->li_usage.pr_vctx;
414 lwp->li_ictx = usage_buf->pr_ictx - lwp->li_usage.pr_ictx;
415 lwp->li_scl = usage_buf->pr_sysc - lwp->li_usage.pr_sysc;
416 lwp->li_ioch = usage_buf->pr_ioch - lwp->li_usage.pr_ioch;
417 lwp->li_timestamp = TIME2NSEC(usage_buf->pr_tstamp);
418 (void) memcpy(&lwp->li_usage, usage_buf, sizeof (prusage_t));
419 }
420
421
422 /*
423 * This is the meat of the /proc scanner.
424 * It will visit every single LWP in /proc.
425 */
426 static void
collect_lwp_data()427 collect_lwp_data()
428 {
429 char *pidstr;
430 pid_t pid;
431 id_t lwpid;
432 size_t entsz;
433 long nlwps, nent, i;
434 char *buf, *ptr;
435 char pfile[MAX_PROCFS_PATH];
436
437 fds_t *fds;
438 lwp_info_t *lwp;
439
440 dirent_t *direntp;
441
442 prheader_t header_buf;
443 psinfo_t psinfo_buf;
444 prusage_t usage_buf;
445 lwpsinfo_t *lwpsinfo_buf;
446 prusage_t *lwpusage_buf;
447
448 log_msg("->collect_lwp_data(): %d files open\n", fd_count());
449 for (rewinddir(procdir); (direntp = readdir(procdir)); ) {
450 pidstr = direntp->d_name;
451 if (pidstr[0] == '.') /* skip "." and ".." */
452 continue;
453 pid = atoi(pidstr);
454 if (pid == 0 || pid == 2 || pid == 3)
455 continue; /* skip sched, pageout and fsflush */
456
457 fds = fds_get(pid); /* get ptr to file descriptors */
458
459 /*
460 * Here we are going to read information about
461 * current process (pid) from /proc/pid/psinfo file.
462 * If process has more than one lwp, we also should
463 * read /proc/pid/lpsinfo for information about all lwps.
464 */
465 (void) snprintf(pfile, MAX_PROCFS_PATH,
466 "/proc/%s/psinfo", pidstr);
467 if ((fds->fds_psinfo = fd_open(pfile, O_RDONLY,
468 fds->fds_psinfo)) == NULL)
469 continue;
470 if (pread(fd_getfd(fds->fds_psinfo), &psinfo_buf,
471 sizeof (struct psinfo), 0) != sizeof (struct psinfo)) {
472 fd_close(fds->fds_psinfo);
473 continue;
474 }
475
476 fd_close(fds->fds_psinfo);
477
478 nlwps = psinfo_buf.pr_nlwp + psinfo_buf.pr_nzomb;
479 if (nlwps > 1) {
480 (void) snprintf(pfile, MAX_PROCFS_PATH,
481 "/proc/%s/lpsinfo", pidstr);
482 if ((fds->fds_lpsinfo = fd_open(pfile, O_RDONLY,
483 fds->fds_lpsinfo)) == NULL)
484 continue;
485 entsz = sizeof (struct prheader);
486 if (pread(fd_getfd(fds->fds_lpsinfo), &header_buf,
487 entsz, 0) != entsz) {
488 fd_close(fds->fds_lpsinfo);
489 continue;
490 }
491 nent = header_buf.pr_nent;
492 entsz = header_buf.pr_entsize * nent;
493 ptr = buf = Malloc(entsz);
494 if (pread(fd_getfd(fds->fds_lpsinfo), buf,
495 entsz, sizeof (struct prheader)) != entsz) {
496 fd_close(fds->fds_lpsinfo);
497 Free(buf);
498 continue;
499 }
500
501 fd_close(fds->fds_lpsinfo);
502
503 for (i = 0; i < nent;
504 i++, ptr += header_buf.pr_entsize) {
505 /*LINTED ALIGNMENT*/
506 lwpsinfo_buf = (lwpsinfo_t *)ptr;
507 lwpid = lwpsinfo_buf->pr_lwpid;
508 if ((lwp = lwpid_get(pid, lwpid)) == NULL) {
509 lwp = list_add_lwp(&lwps, pid, lwpid);
510 }
511 if (i == 0)
512 lwp->rlwpid = lwpid;
513 (void) memcpy(lwp->li_psinfo, &psinfo_buf,
514 sizeof (psinfo_t) - sizeof (lwpsinfo_t));
515 lwp->li_alive = B_TRUE;
516 (void) memcpy(lwp->li_lwpsinfo,
517 lwpsinfo_buf, sizeof (lwpsinfo_t));
518 }
519 Free(buf);
520 } else {
521 lwpid = psinfo_buf.pr_lwp.pr_lwpid;
522 if ((lwp = lwpid_get(pid, lwpid)) == NULL) {
523 lwp = list_add_lwp(&lwps, pid, lwpid);
524 }
525 lwp->rlwpid = lwpid;
526 (void) memcpy(lwp->li_psinfo, &psinfo_buf,
527 sizeof (psinfo_t) - sizeof (lwpsinfo_t));
528 lwp->li_alive = B_TRUE;
529 (void) memcpy(lwp->li_lwpsinfo,
530 &psinfo_buf.pr_lwp, sizeof (lwpsinfo_t));
531 lwp->li_lwpsinfo->pr_pctcpu = lwp->li_psinfo->pr_pctcpu;
532 }
533
534 /*
535 * At this part of scandir we read additional information
536 * about processes from /proc/pid/usage file.
537 * Again, if process has more than one lwp, then we
538 * will get information about all its lwps from
539 * /proc/pid/lusage file.
540 */
541 if (nlwps > 1) {
542 (void) snprintf(pfile, MAX_PROCFS_PATH,
543 "/proc/%s/lusage", pidstr);
544 if ((fds->fds_lusage = fd_open(pfile, O_RDONLY,
545 fds->fds_lusage)) == NULL)
546 continue;
547 entsz = sizeof (struct prheader);
548 if (pread(fd_getfd(fds->fds_lusage), &header_buf,
549 entsz, 0) != entsz) {
550 fd_close(fds->fds_lusage);
551 continue;
552 }
553
554 nent = header_buf.pr_nent;
555 entsz = header_buf.pr_entsize * nent;
556 buf = Malloc(entsz);
557 if (pread(fd_getfd(fds->fds_lusage), buf,
558 entsz, sizeof (struct prheader)) != entsz) {
559 fd_close(fds->fds_lusage);
560 Free(buf);
561 continue;
562 }
563
564 fd_close(fds->fds_lusage);
565
566 for (i = 1, ptr = buf + header_buf.pr_entsize; i < nent;
567 i++, ptr += header_buf.pr_entsize) {
568 /*LINTED ALIGNMENT*/
569 lwpusage_buf = (prusage_t *)ptr;
570 lwpid = lwpusage_buf->pr_lwpid;
571 if ((lwp = lwpid_get(pid, lwpid)) == NULL)
572 continue;
573 lwp_update(lwp, lwpusage_buf);
574 }
575 Free(buf);
576 } else {
577 (void) snprintf(pfile, MAX_PROCFS_PATH,
578 "/proc/%s/usage", pidstr);
579 if ((fds->fds_usage = fd_open(pfile, O_RDONLY,
580 fds->fds_usage)) == NULL)
581 continue;
582 entsz = sizeof (prusage_t);
583 if (pread(fd_getfd(fds->fds_usage), &usage_buf,
584 entsz, 0) != entsz) {
585 fd_close(fds->fds_usage);
586 continue;
587 }
588
589 fd_close(fds->fds_usage);
590
591 lwpid = psinfo_buf.pr_lwp.pr_lwpid;
592 if ((lwp = lwpid_get(pid, lwpid)) == NULL)
593 continue;
594 lwp_update(lwp, &usage_buf);
595 }
596 }
597 list_refresh(&lwps);
598 fd_update();
599 log_msg("<-collect_lwp_data(): %d files open\n", fd_count());
600 }
601
602
603 /*
604 * Create linked lists of users, projects and sets.
605 *
606 * Updates of the process, users and projects lists are done in
607 * a critical section so that the consumer of these lists will
608 * always get consistent data.
609 */
610 static void
list_create()611 list_create()
612 {
613 struct utsname utsn;
614 lwp_info_t *lwp;
615 hrtime_t t1, t2, t3;
616 double d;
617 int rv;
618
619 lwp = lwps.l_head;
620 total_mem = 0;
621 total_cpu = 0;
622 log_msg("->list_create()\n");
623 t1 = gethrtime();
624 if ((rv = pthread_mutex_lock(&listLock)) == 0) {
625 t2 = gethrtime();
626 d = (double)(t2 - t1) / 1000000000.0;
627 log_msg("Scanner process lock wait was %1.5f sec\n", d);
628
629 while (lwp) {
630 list_update(&processes, lwp);
631 list_update(&users, lwp);
632 list_update(&projects, lwp);
633 lwp = lwp->li_next;
634 }
635 list_refresh_id(&processes);
636 list_refresh_id(&users);
637 list_refresh_id(&projects);
638 /* release the mutex */
639 if ((rv = pthread_mutex_unlock(&listLock)) != 0)
640 log_msg("pthread_mutex_unlock failed with %d\n", rv);
641
642 t3 = gethrtime();
643
644 d = (double)(t3 - t2) / 1000000000.0;
645 log_msg("Scanner process lock time was %1.5f sec\n", d);
646
647 } else {
648 log_msg("pthread_mutex_lock failed with %d\n", rv);
649 }
650
651 if (uname(&utsn) != -1) {
652 sys_info.name =
653 Realloc(sys_info.name, strlen(utsn.sysname) + 1);
654 (void) strcpy(sys_info.name, utsn.sysname);
655 sys_info.nodename =
656 Realloc(sys_info.nodename, strlen(utsn.nodename) + 1);
657 (void) strcpy(sys_info.nodename, utsn.nodename);
658 } else {
659 log_err("uname()\n");
660 }
661
662 log_msg("<-list_create()\n");
663 }
664
665
666 static void
collect_data()667 collect_data() {
668
669 collect_lwp_data();
670 if (getloadavg(loadavg, 3) == -1)
671 dmerror("cannot get load average\n");
672 }
673
674
675 void
monitor_stop()676 monitor_stop()
677 {
678 /* store the list state */
679 if (ltdb_file != NULL)
680 (void) list_store(ltdb_file);
681 list_clear(&lwps);
682 list_clear(&processes);
683 list_clear(&users);
684 list_clear(&projects);
685 fd_exit();
686 }
687
688
689 /*
690 * Initialize the monitor.
691 * Creates list data structures.
692 * If a saved list data file exists it is loaded.
693 * The /proc directory is opened.
694 * No actual scanning of /proc is done.
695 *
696 * Returns 0 if OK or -1 on error (leaving errno unchanged)
697 */
698 int
monitor_start()699 monitor_start()
700 {
701
702 if (setjmp(dm_jmpbuffer) == 0) {
703 lwpid_init();
704 fd_init(Setrlimit());
705
706 list_alloc(&lwps, LS_LWPS);
707 list_alloc(&processes, LT_PROCESS);
708 list_alloc(&users, LS_USERS);
709 list_alloc(&projects, LS_PROJECTS);
710
711 list_init(&lwps, LT_LWPS);
712 list_init(&processes, LT_PROCESS);
713 list_init(&users, LT_USERS);
714 list_init(&projects, LT_PROJECTS);
715
716 sys_info.name = NULL;
717 sys_info.nodename = NULL;
718
719 if ((procdir = opendir("/proc")) == NULL)
720 dmerror("cannot open /proc directory\n");
721
722 /* restore the lists state */
723 if (ltdb_file != NULL)
724 (void) list_restore(ltdb_file);
725
726 return (0);
727 } else {
728 return (-1);
729 }
730 }
731
732
733 /*
734 * Update the monitor data lists.
735 * return 0, or -1 on error and leave errno unchanged
736 */
737 int
monitor_update()738 monitor_update()
739 {
740 if (setjmp(dm_jmpbuffer) == 0) {
741 collect_data();
742 list_create();
743 return (0);
744 } else {
745 return (-1);
746 }
747 }
748