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