1 /* 2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "jvm.h" 27 #include "memory/allocation.inline.hpp" 28 #include "runtime/os.hpp" 29 #include "runtime/os_perf.hpp" 30 #include "os_solaris.inline.hpp" 31 #include "utilities/macros.hpp" 32 33 #include CPU_HEADER(vm_version_ext) 34 35 #include <sys/types.h> 36 #include <procfs.h> 37 #include <dirent.h> 38 #include <errno.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <strings.h> 42 #include <unistd.h> 43 #include <fcntl.h> 44 #include <kstat.h> 45 #include <unistd.h> 46 #include <string.h> 47 #include <sys/sysinfo.h> 48 #include <sys/lwp.h> 49 #include <pthread.h> 50 #include <time.h> 51 #include <utmpx.h> 52 #include <dlfcn.h> 53 #include <sys/loadavg.h> 54 #include <limits.h> 55 56 static const double NANOS_PER_SEC = 1000000000.0; 57 58 struct CPUPerfTicks { 59 kstat_t* kstat; 60 uint64_t last_idle; 61 uint64_t last_total; 62 double last_ratio; 63 }; 64 65 struct CPUPerfCounters { 66 int nProcs; 67 CPUPerfTicks* jvmTicks; 68 kstat_ctl_t* kstat_ctrl; 69 }; 70 71 static int get_info(const char* path, void* info, size_t s, off_t o) { 72 assert(path != NULL, "path is NULL!"); 73 assert(info != NULL, "info is NULL!"); 74 75 int fd = -1; 76 77 if ((fd = open(path, O_RDONLY)) < 0) { 78 return OS_ERR; 79 } 80 if (pread(fd, info, s, o) != s) { 81 close(fd); 82 return OS_ERR; 83 } 84 close(fd); 85 return OS_OK; 86 } 87 88 static int get_psinfo2(void* info, size_t s, off_t o) { 89 return get_info("/proc/self/psinfo", info, s, o); 90 } 91 92 static int get_psinfo(psinfo_t* info) { 93 return get_psinfo2(info, sizeof(*info), 0); 94 } 95 96 static int get_psinfo(char* file, psinfo_t* info) { 97 assert(file != NULL, "file is NULL!"); 98 assert(info != NULL, "info is NULL!"); 99 return get_info(file, info, sizeof(*info), 0); 100 } 101 102 103 static int get_usage(prusage_t* usage) { 104 assert(usage != NULL, "usage is NULL!"); 105 return get_info("/proc/self/usage", usage, sizeof(*usage), 0); 106 } 107 108 static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) { 109 assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!"); 110 assert(load != NULL, "load pointer is NULL!"); 111 assert(cpu_stat != NULL, "cpu_stat pointer is NULL!"); 112 113 if (load->kstat == NULL) { 114 // no handle. 115 return OS_ERR; 116 } 117 if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) { 118 // disable handle for this CPU 119 load->kstat = NULL; 120 return OS_ERR; 121 } 122 return OS_OK; 123 } 124 125 static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) { 126 assert(counters != NULL, "counters pointer is NULL!"); 127 128 cpu_stat_t cpu_stat = {0}; 129 130 if (which_logical_cpu >= counters->nProcs) { 131 return .0; 132 } 133 134 CPUPerfTicks load = counters->jvmTicks[which_logical_cpu]; 135 if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) { 136 return .0; 137 } 138 139 uint_t* usage = cpu_stat.cpu_sysinfo.cpu; 140 if (usage == NULL) { 141 return .0; 142 } 143 144 uint64_t c_idle = usage[CPU_IDLE]; 145 uint64_t c_total = 0; 146 147 for (int i = 0; i < CPU_STATES; i++) { 148 c_total += usage[i]; 149 } 150 151 // Calculate diff against previous snapshot 152 uint64_t d_idle = c_idle - load.last_idle; 153 uint64_t d_total = c_total - load.last_total; 154 155 /** update if weve moved */ 156 if (d_total > 0) { 157 // Save current values for next time around 158 load.last_idle = c_idle; 159 load.last_total = c_total; 160 load.last_ratio = (double) (d_total - d_idle) / d_total; 161 } 162 163 return load.last_ratio; 164 } 165 166 static int get_boot_time(uint64_t* time) { 167 assert(time != NULL, "time pointer is NULL!"); 168 setutxent(); 169 for(;;) { 170 struct utmpx* u; 171 if ((u = getutxent()) == NULL) { 172 break; 173 } 174 if (u->ut_type == BOOT_TIME) { 175 *time = u->ut_xtime; 176 endutxent(); 177 return OS_OK; 178 } 179 } 180 endutxent(); 181 return OS_ERR; 182 } 183 184 static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) { 185 assert(switches != NULL, "switches pointer is NULL!"); 186 assert(counters != NULL, "counter pointer is NULL!"); 187 *switches = 0; 188 uint64_t s = 0; 189 190 // Collect data from all CPUs 191 for (int i = 0; i < counters->nProcs; i++) { 192 cpu_stat_t cpu_stat = {0}; 193 CPUPerfTicks load = counters->jvmTicks[i]; 194 195 if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) { 196 s += cpu_stat.cpu_sysinfo.pswitch; 197 } else { 198 //fail fast... 199 return OS_ERR; 200 } 201 } 202 *switches = s; 203 return OS_OK; 204 } 205 206 static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) { 207 assert(counters != NULL, "counters is NULL!"); 208 assert(rate != NULL, "rate pointer is NULL!"); 209 static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER; 210 static uint64_t lastTime = 0; 211 static uint64_t lastSwitches = 0; 212 static double lastRate = 0.0; 213 214 uint64_t lt = 0; 215 int res = 0; 216 217 if (lastTime == 0) { 218 uint64_t tmp; 219 if (get_boot_time(&tmp) < 0) { 220 return OS_ERR; 221 } 222 lt = tmp * 1000; 223 } 224 225 res = OS_OK; 226 227 pthread_mutex_lock(&contextSwitchLock); 228 { 229 230 uint64_t sw = 0; 231 clock_t t, d; 232 233 if (lastTime == 0) { 234 lastTime = lt; 235 } 236 237 t = clock(); 238 d = t - lastTime; 239 240 if (d == 0) { 241 *rate = lastRate; 242 } else if (get_noof_context_switches(counters, &sw)== OS_OK) { 243 *rate = ((double)(sw - lastSwitches) / d) * 1000; 244 lastRate = *rate; 245 lastSwitches = sw; 246 lastTime = t; 247 } else { 248 *rate = 0.0; 249 res = OS_ERR; 250 } 251 if (*rate < 0.0) { 252 *rate = 0.0; 253 lastRate = 0.0; 254 } 255 } 256 pthread_mutex_unlock(&contextSwitchLock); 257 return res; 258 } 259 260 261 262 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> { 263 friend class CPUPerformanceInterface; 264 private: 265 CPUPerfCounters _counters; 266 int cpu_load(int which_logical_cpu, double* cpu_load); 267 int context_switch_rate(double* rate); 268 int cpu_load_total_process(double* cpu_load); 269 int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); 270 271 CPUPerformance(); 272 ~CPUPerformance(); 273 bool initialize(); 274 }; 275 276 CPUPerformanceInterface::CPUPerformance::CPUPerformance() { 277 _counters.nProcs = 0; 278 _counters.jvmTicks = NULL; 279 _counters.kstat_ctrl = NULL; 280 } 281 282 bool CPUPerformanceInterface::CPUPerformance::initialize() { 283 // initialize kstat control structure, 284 _counters.kstat_ctrl = kstat_open(); 285 assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!"); 286 287 if (NULL == _counters.kstat_ctrl) { 288 return false; 289 } 290 291 // Get number of CPU(s) 292 if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) { 293 // ignore error? 294 _counters.nProcs = 1; 295 } 296 297 assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!"); 298 if (_counters.nProcs == 0) { 299 return false; 300 } 301 302 // Data structure(s) for saving CPU load (one per CPU) 303 size_t tick_array_size = _counters.nProcs * sizeof(CPUPerfTicks); 304 _counters.jvmTicks = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal); 305 if (NULL == _counters.jvmTicks) { 306 return false; 307 } 308 memset(_counters.jvmTicks, 0, tick_array_size); 309 310 // Get kstat cpu_stat counters for every CPU 311 // loop over kstat to find our cpu_stat(s) 312 int i = 0; 313 for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) { 314 if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) { 315 if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) { 316 continue; 317 } 318 if (i == _counters.nProcs) { 319 // more cpu_stats than reported CPUs 320 break; 321 } 322 _counters.jvmTicks[i++].kstat = kstat; 323 } 324 } 325 return true; 326 } 327 328 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { 329 if (_counters.jvmTicks != NULL) { 330 FREE_C_HEAP_ARRAY(char, _counters.jvmTicks); 331 } 332 if (_counters.kstat_ctrl != NULL) { 333 kstat_close(_counters.kstat_ctrl); 334 } 335 } 336 337 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { 338 assert(cpu_load != NULL, "cpu_load pointer is NULL!"); 339 double t = .0; 340 if (-1 == which_logical_cpu) { 341 for (int i = 0; i < _counters.nProcs; i++) { 342 t += get_cpu_load(i, &_counters); 343 } 344 // Cap total systemload to 1.0 345 t = MIN2<double>((t / _counters.nProcs), 1.0); 346 } else { 347 t = MIN2<double>(get_cpu_load(which_logical_cpu, &_counters), 1.0); 348 } 349 350 *cpu_load = t; 351 return OS_OK; 352 } 353 354 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) { 355 assert(cpu_load != NULL, "cpu_load pointer is NULL!"); 356 357 psinfo_t info; 358 359 // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s 360 // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000. 361 if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) { 362 *cpu_load = 0.0; 363 return OS_ERR; 364 } 365 *cpu_load = (double) info.pr_pctcpu / 0x8000; 366 return OS_OK; 367 } 368 369 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) { 370 assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited"); 371 assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited"); 372 assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited"); 373 374 static uint64_t lastTime; 375 static uint64_t lastUser, lastKernel; 376 static double lastUserRes, lastKernelRes; 377 378 pstatus_t pss; 379 psinfo_t info; 380 381 *pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0; 382 if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) { 383 return OS_ERR; 384 } 385 386 if (get_psinfo(&info) != 0) { 387 return OS_ERR; 388 } 389 390 // get the total time in user, kernel and total time 391 // check ratios for 'lately' and multiply the 'recent load'. 392 uint64_t time = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec; 393 uint64_t user = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec; 394 uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec; 395 uint64_t diff = time - lastTime; 396 double load = (double) info.pr_pctcpu / 0x8000; 397 398 if (diff > 0) { 399 lastUserRes = (load * (user - lastUser)) / diff; 400 lastKernelRes = (load * (kernel - lastKernel)) / diff; 401 402 // BUG9182835 - patch for clamping these values to sane ones. 403 lastUserRes = MIN2<double>(1, lastUserRes); 404 lastUserRes = MAX2<double>(0, lastUserRes); 405 lastKernelRes = MIN2<double>(1, lastKernelRes); 406 lastKernelRes = MAX2<double>(0, lastKernelRes); 407 } 408 409 double t = .0; 410 cpu_load(-1, &t); 411 // clamp at user+system and 1.0 412 if (lastUserRes + lastKernelRes > t) { 413 t = MIN2<double>(lastUserRes + lastKernelRes, 1.0); 414 } 415 416 *pjvmUserLoad = lastUserRes; 417 *pjvmKernelLoad = lastKernelRes; 418 *psystemTotalLoad = t; 419 420 lastTime = time; 421 lastUser = user; 422 lastKernel = kernel; 423 424 return OS_OK; 425 } 426 427 int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { 428 return perf_context_switch_rate(&_counters, rate); 429 } 430 431 CPUPerformanceInterface::CPUPerformanceInterface() { 432 _impl = NULL; 433 } 434 435 bool CPUPerformanceInterface::initialize() { 436 _impl = new CPUPerformanceInterface::CPUPerformance(); 437 return _impl != NULL && _impl->initialize(); 438 } 439 440 CPUPerformanceInterface::~CPUPerformanceInterface(void) { 441 if (_impl != NULL) { 442 delete _impl; 443 } 444 } 445 446 int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const { 447 return _impl->cpu_load(which_logical_cpu, cpu_load); 448 } 449 450 int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const { 451 return _impl->cpu_load_total_process(cpu_load); 452 } 453 454 int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const { 455 return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad); 456 } 457 458 int CPUPerformanceInterface::context_switch_rate(double* rate) const { 459 return _impl->context_switch_rate(rate); 460 } 461 462 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> { 463 friend class SystemProcessInterface; 464 private: 465 class ProcessIterator : public CHeapObj<mtInternal> { 466 friend class SystemProcessInterface::SystemProcesses; 467 private: 468 DIR* _dir; 469 struct dirent* _entry; 470 bool _valid; 471 472 ProcessIterator(); 473 ~ProcessIterator(); 474 bool initialize(); 475 476 bool is_valid() const { return _valid; } 477 bool is_valid_entry(struct dirent* const entry) const; 478 bool is_dir(const char* const name) const; 479 char* allocate_string(const char* const str) const; 480 int current(SystemProcess* const process_info); 481 int next_process(); 482 }; 483 484 ProcessIterator* _iterator; 485 SystemProcesses(); 486 bool initialize(); 487 ~SystemProcesses(); 488 489 //information about system processes 490 int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const; 491 }; 492 493 bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const { 494 struct stat64 mystat; 495 int ret_val = 0; 496 497 ret_val = ::stat64(name, &mystat); 498 499 if (ret_val < 0) { 500 return false; 501 } 502 ret_val = S_ISDIR(mystat.st_mode); 503 return ret_val > 0; 504 } 505 506 // if it has a numeric name, is a directory and has a 'psinfo' file in it 507 bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const { 508 // ignore the "." and ".." directories 509 if ((strcmp(entry->d_name, ".") == 0) || 510 (strcmp(entry->d_name, "..") == 0)) { 511 return false; 512 } 513 514 char buffer[PATH_MAX] = {0}; 515 uint64_t size = 0; 516 bool result = false; 517 FILE *fp = NULL; 518 519 if (atoi(entry->d_name) != 0) { 520 jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name); 521 522 if (is_dir(buffer)) { 523 memset(buffer, 0, PATH_MAX); 524 jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name); 525 if ((fp = fopen(buffer, "r")) != NULL) { 526 int nread = 0; 527 psinfo_t psinfo_data; 528 if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) { 529 // only considering system process owned by root 530 if (psinfo_data.pr_uid == 0) { 531 result = true; 532 } 533 } 534 } 535 } 536 } 537 538 if (fp != NULL) { 539 fclose(fp); 540 } 541 542 return result; 543 } 544 545 char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const { 546 if (str != NULL) { 547 size_t len = strlen(str); 548 char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal); 549 strncpy(tmp, str, len); 550 tmp[len] = '\0'; 551 return tmp; 552 } 553 return NULL; 554 } 555 556 int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) { 557 if (!is_valid()) { 558 return OS_ERR; 559 } 560 561 char psinfo_path[PATH_MAX] = {0}; 562 jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name); 563 564 FILE *fp = NULL; 565 if ((fp = fopen(psinfo_path, "r")) == NULL) { 566 return OS_ERR; 567 } 568 569 int nread = 0; 570 psinfo_t psinfo_data; 571 if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) { 572 fclose(fp); 573 return OS_ERR; 574 } 575 576 char *exe_path = NULL; 577 if ((psinfo_data.pr_fname != NULL) && 578 (psinfo_data.pr_psargs != NULL)) { 579 char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname); 580 if (path_substring != NULL) { 581 int len = path_substring - psinfo_data.pr_psargs; 582 exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal); 583 if (exe_path != NULL) { 584 jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs); 585 exe_path[len] = '\0'; 586 } 587 } 588 } 589 590 process_info->set_pid(atoi(_entry->d_name)); 591 process_info->set_name(allocate_string(psinfo_data.pr_fname)); 592 process_info->set_path(allocate_string(exe_path)); 593 process_info->set_command_line(allocate_string(psinfo_data.pr_psargs)); 594 595 if (exe_path != NULL) { 596 FREE_C_HEAP_ARRAY(char, exe_path); 597 } 598 599 if (fp != NULL) { 600 fclose(fp); 601 } 602 603 return OS_OK; 604 } 605 606 int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() { 607 struct dirent* entry; 608 609 if (!is_valid()) { 610 return OS_ERR; 611 } 612 613 do { 614 if ((entry = os::readdir(_dir, _entry)) == NULL) { 615 // error 616 _valid = false; 617 return OS_ERR; 618 } 619 } while(!is_valid_entry(_entry)); 620 621 _valid = true; 622 return OS_OK; 623 } 624 625 SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() { 626 _dir = NULL; 627 _entry = NULL; 628 _valid = false; 629 } 630 631 bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() { 632 _dir = opendir("/proc"); 633 _entry = (struct dirent*)NEW_C_HEAP_ARRAY(char, sizeof(struct dirent) + _PC_NAME_MAX + 1, mtInternal); 634 if (NULL == _entry) { 635 return false; 636 } 637 _valid = true; 638 next_process(); 639 640 return true; 641 } 642 643 SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() { 644 if (_entry != NULL) { 645 FREE_C_HEAP_ARRAY(char, _entry); 646 } 647 648 if (_dir != NULL) { 649 closedir(_dir); 650 } 651 } 652 653 SystemProcessInterface::SystemProcesses::SystemProcesses() { 654 _iterator = NULL; 655 } 656 657 bool SystemProcessInterface::SystemProcesses::initialize() { 658 _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator(); 659 return _iterator != NULL && _iterator->initialize(); 660 } 661 662 SystemProcessInterface::SystemProcesses::~SystemProcesses() { 663 if (_iterator != NULL) { 664 delete _iterator; 665 } 666 } 667 668 int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const { 669 assert(system_processes != NULL, "system_processes pointer is NULL!"); 670 assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!"); 671 assert(_iterator != NULL, "iterator is NULL!"); 672 673 // initialize pointers 674 *no_of_sys_processes = 0; 675 *system_processes = NULL; 676 677 while (_iterator->is_valid()) { 678 SystemProcess* tmp = new SystemProcess(); 679 _iterator->current(tmp); 680 681 //if already existing head 682 if (*system_processes != NULL) { 683 //move "first to second" 684 tmp->set_next(*system_processes); 685 } 686 // new head 687 *system_processes = tmp; 688 // increment 689 (*no_of_sys_processes)++; 690 // step forward 691 _iterator->next_process(); 692 } 693 return OS_OK; 694 } 695 696 int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const { 697 return _impl->system_processes(system_procs, no_of_sys_processes); 698 } 699 700 SystemProcessInterface::SystemProcessInterface() { 701 _impl = NULL; 702 } 703 704 bool SystemProcessInterface::initialize() { 705 _impl = new SystemProcessInterface::SystemProcesses(); 706 return _impl != NULL && _impl->initialize(); 707 708 } 709 710 SystemProcessInterface::~SystemProcessInterface() { 711 if (_impl != NULL) { 712 delete _impl; 713 } 714 } 715 716 CPUInformationInterface::CPUInformationInterface() { 717 _cpu_info = NULL; 718 } 719 720 bool CPUInformationInterface::initialize() { 721 _cpu_info = new CPUInformation(); 722 if (_cpu_info == NULL) { 723 return false; 724 } 725 _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads()); 726 _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores()); 727 _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets()); 728 _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name()); 729 _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description()); 730 return true; 731 } 732 733 CPUInformationInterface::~CPUInformationInterface() { 734 if (_cpu_info != NULL) { 735 if (_cpu_info->cpu_name() != NULL) { 736 const char* cpu_name = _cpu_info->cpu_name(); 737 FREE_C_HEAP_ARRAY(char, cpu_name); 738 _cpu_info->set_cpu_name(NULL); 739 } 740 if (_cpu_info->cpu_description() != NULL) { 741 const char* cpu_desc = _cpu_info->cpu_description(); 742 FREE_C_HEAP_ARRAY(char, cpu_desc); 743 _cpu_info->set_cpu_description(NULL); 744 } 745 delete _cpu_info; 746 } 747 } 748 749 int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) { 750 if (_cpu_info == NULL) { 751 return OS_ERR; 752 } 753 754 cpu_info = *_cpu_info; // shallow copy assignment 755 return OS_OK; 756 }