/*
* Copyright (C), 2000-2007 by the monit project group.
* All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#ifdef HAVE_ERRNO_H
#include
#endif
#ifdef HAVE_STRING_H
#include
#endif
#ifdef HAVE_FCNTL_H
#include
#endif
#ifdef HAVE_KVM_H
#include
#endif
#ifdef HAVE_SYS_SYSCTL_H
#include
#endif
#ifdef HAVE_SYS_VMMETER_H
#include
#endif
#ifdef HAVE_MACH_MACH_H
#include
#endif
#ifdef HAVE_MACH_HOST_INFO_H
#include
#endif
#ifdef HAVE_MACH_MACH_HOST_H
#include
#endif
#include "monitor.h"
#include "process.h"
#include "process_sysdep.h"
/**
* System dependent resource gathering code for MacOS X.
*
* @author Jan-Henrik Haukeland,
* @author Christian Hopp
* @author Rory Toma
* @author Martin Pala
* @author Dave Cheney (Updated for Tiger)
*
* @version \$Id: sysdep_DARWIN.c,v 1.36 2007/11/05 21:50:04 hauk Exp $
*
* @file
*/
/* ----------------------------------------------------------------- Private */
static int hz;
static int pagesize_kbyte;
static long total_old = 0;
static long cpu_user_old = 0;
static long cpu_syst_old = 0;
/* ------------------------------------------------------------------ Public */
int init_process_info_sysdep(void) {
int mib[2];
size_t len;
struct clockinfo clock;
uint64_t memsize;
mib[0] = CTL_KERN;
mib[1] = KERN_CLOCKRATE;
len = sizeof(clock);
if(sysctl(mib, 2, &clock, &len, NULL, 0) == -1)
{
DEBUG("system statistic error -- cannot get clock rate: %s\n", STRERROR);
return FALSE;
}
hz = clock.hz;
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(num_cpus);
if(sysctl(mib, 2, &num_cpus, &len, NULL, 0) == -1)
{
DEBUG("system statistic error -- cannot get cpu count: %s\n", STRERROR);
return FALSE;
}
mib[1] = HW_MEMSIZE;
len = sizeof(memsize);
memsize = 0L;
if(sysctl(mib, 2, &memsize, &len, NULL, 0 ) == -1)
{
DEBUG("system statistic error -- cannot get real memory amount: %s\n", STRERROR);
return FALSE;
}
systeminfo.mem_kbyte_max = memsize / 1024;
mib[1] = HW_PAGESIZE;
len = sizeof(pagesize_kbyte);
if(sysctl(mib, 2, &pagesize_kbyte, &len, NULL, 0) == -1)
{
DEBUG("system statistic error -- cannot get memory page size: %s\n", STRERROR);
return FALSE;
}
pagesize_kbyte /= 1024;
return TRUE;
}
/**
* Read all processes to initialize the information tree.
* @param reference reference of ProcessTree
* @return treesize>0 if succeeded otherwise =0.
*/
int initprocesstree_sysdep(ProcessTree_T **reference) {
int i;
int treesize;
mach_port_t mytask = mach_task_self();
struct kinfo_proc *pinfo;
ProcessTree_T *pt;
size_t bufSize = 0;
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
if(getuid()!=0) {
LogError("system statistic error -- permission denied\n");
return FALSE;
}
if(sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
LogError("system statistic error -- sysctl failed");
return FALSE;
}
pinfo = (struct kinfo_proc *)xcalloc(1, bufSize);
if(sysctl(mib, 4, pinfo, &bufSize, NULL, 0)) {
LogError("system statistic error -- sysctl failed");
free(pinfo);
return FALSE;
}
treesize = bufSize / sizeof(struct kinfo_proc);
pt = xcalloc(sizeof(ProcessTree_T), treesize);
for(i = 0; i < treesize; i++)
{
mach_port_t task;
pt[i].pid = pinfo[i].kp_proc.p_pid;
pt[i].ppid = pinfo[i].kp_eproc.e_ppid;
if(pinfo[i].kp_proc.p_stat == SZOMB) {
pt[i].status_flag |= PROCESS_ZOMBIE;
}
pt[i].time = get_float_time();
if(task_for_pid(mytask, pt[i].pid, &task) == KERN_SUCCESS) {
mach_msg_type_number_t count;
task_basic_info_data_t taskinfo;
thread_array_t threadtable;
unsigned int threadtable_size;
thread_basic_info_t threadinfo;
thread_basic_info_data_t threadinfo_data;
count = TASK_BASIC_INFO_COUNT;
if(task_info(task, TASK_BASIC_INFO, (task_info_t)&taskinfo, &count) == KERN_SUCCESS) {
pt[i].mem_kbyte = (unsigned long)(taskinfo.resident_size / 1024);
pt[i].cputime = (long)((taskinfo.user_time.seconds + taskinfo.system_time.seconds) * 10 +
(taskinfo.user_time.microseconds + taskinfo.system_time.microseconds) / 100000);
}
if(task_threads(task, &threadtable, &threadtable_size) == KERN_SUCCESS) {
int j;
threadinfo = &threadinfo_data;
for(j = 0; j < threadtable_size; j++) {
count = THREAD_BASIC_INFO_COUNT;
if(thread_info(threadtable[j], THREAD_BASIC_INFO, (thread_info_t)threadinfo, &count) == KERN_SUCCESS) {
if((threadinfo->flags & TH_FLAGS_IDLE) == 0) {
pt[i].cputime += (long)((threadinfo->user_time.seconds + threadinfo->system_time.seconds) * 10 +
(threadinfo->user_time.microseconds + threadinfo->system_time.microseconds) / 100000);
}
}
mach_port_deallocate(mytask, threadtable[j]);
}
vm_deallocate(mytask, (vm_address_t)threadtable,threadtable_size * sizeof(thread_act_t));
}
mach_port_deallocate(mytask, task);
}
}
*reference = pt;
free(pinfo);
return treesize;
}
/**
* This routine returns 'nelem' double precision floats containing
* the load averages in 'loadv'; at most 3 values will be returned.
* @param loadv destination of the load averages
* @param nelem number of averages
* @return: 0 if successful, -1 if failed (and all load averages are 0).
*/
int getloadavg_sysdep (double *loadv, int nelem) {
return getloadavg(loadv, nelem);
}
/**
* This routine returns kbyte of real memory in use.
* @return: TRUE if successful, FALSE if failed (or not available)
*/
int used_system_memory_sysdep(SystemInfo_T *si) {
kern_return_t kret;
vm_statistics_data_t page_info;
mach_msg_type_number_t count;
count = HOST_VM_INFO_COUNT;
kret = host_statistics(
mach_host_self(), HOST_VM_INFO, (host_info_t)&page_info, &count
);
if(kret == KERN_SUCCESS)
{
unsigned int pw, pa, pi;
pw = page_info.wire_count * pagesize_kbyte;
pa = page_info.active_count * pagesize_kbyte;
pi = page_info.inactive_count * pagesize_kbyte;
si->total_mem_kbyte = pw+pa+pi;
return TRUE;
}
return FALSE;
}
/**
* This routine returns system/user CPU time in use.
* @return: TRUE if successful, FALSE if failed
*/
int used_system_cpu_sysdep(SystemInfo_T *si) {
int i;
long total;
long total_new = 0;
kern_return_t kret;
host_cpu_load_info_data_t cpu_info;
mach_msg_type_number_t count;
count = HOST_CPU_LOAD_INFO_COUNT;
kret = host_statistics(
mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpu_info, &count
);
if(kret == KERN_SUCCESS)
{
for(i = 0; i < CPU_STATE_MAX; i++)
{
total_new += cpu_info.cpu_ticks[i];
}
total = total_new - total_old;
total_old = total_new;
si->total_cpu_user_percent =
(total > 0)?(int)(1000 * (double)(cpu_info.cpu_ticks[CPU_STATE_USER] - cpu_user_old) / total):0;
si->total_cpu_syst_percent =
(total > 0)?(int)(1000 * (double)(cpu_info.cpu_ticks[CPU_STATE_SYSTEM] - cpu_syst_old) / total):0;
si->total_cpu_wait_percent =
0; /* there is no wait statistic available */
cpu_user_old = cpu_info.cpu_ticks[CPU_STATE_USER];
cpu_syst_old = cpu_info.cpu_ticks[CPU_STATE_SYSTEM];
return TRUE;
}
return FALSE;
}