xref: /onnv-gate/usr/src/cmd/wbem/provider/tools/rds/rdimpl.c (revision 5006:304eb1332eef)
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