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
58extern pthread_mutex_t listLock;
59
60list_t	lwps;		/* list of lwps/processes */
61list_t	users;		/* list of users */
62list_t	projects;	/* list of projects */
63list_t	processes;	/* list of processes */
64
65sys_info_t sys_info;
66
67jmp_buf dm_jmpbuffer;
68char	errmsg[NL_TEXTMAX];	/* error message max 255 */
69
70static float	total_mem;	/* total memory usage */
71static float	total_cpu;	/* total cpu usage */
72static char *nullstr = "null";
73static double		loadavg[3];
74static DIR		*procdir;
75
76
77/*
78 * Add a LWP entry to the specifed list.
79 */
80lwp_info_t *
81list_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 */
106static void
107list_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 */
131static void
132list_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 */
157void
158list_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 */
190static void
191id_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
282static void
283list_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 */
321static void
322list_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 */
357static void
358list_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 */
382static void
383lwp_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 */
426static void
427collect_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 */
610static void
611list_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
666static void
667collect_data() {
668
669	collect_lwp_data();
670	if (getloadavg(loadavg, 3) == -1)
671		dmerror("cannot get load average\n");
672}
673
674
675void
676monitor_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 */
698int
699monitor_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 */
737int
738monitor_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