blob: 2fd5519976ca07e1bf6cdfc997f9db1371913d24 [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
* @author Mladen Turk
* @version $Revision$, $Date$
*/
#include "apr.h"
#include "apr_pools.h"
#include "apr_network_io.h"
#include "apr_poll.h"
#include "tcn.h"
#if defined(__linux__)
#include <sys/sysinfo.h>
#elif defined(sun)
#include <unistd.h>
#include <sys/swap.h>
#include <procfs.h>
#include <kstat.h>
#include <sys/sysinfo.h>
#endif
#if defined(DARWIN)
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#include <sys/sysctl.h>
#include <sys/stat.h>
#endif
#include <syslog.h>
#include <stdarg.h>
#ifndef LOG_WARN
#define LOG_WARN LOG_WARNING
#endif
#if defined(sun)
#define MAX_PROC_PATH_LEN 64
#define MAX_CPUS 512
#define PSINFO_T_SZ sizeof(psinfo_t)
#define PRUSAGE_T_SZ sizeof(prusage_t)
static int proc_open(const char *type)
{
char proc_path[MAX_PROC_PATH_LEN+1];
sprintf(proc_path, "/proc/self/%s", type);
return open(proc_path, O_RDONLY);
}
static int proc_read(void *buf, const size_t size, int filedes)
{
ssize_t bytes;
if (filedes >= 0) {
bytes = pread(filedes, buf, size, 0);
if (bytes != size)
return -1;
else
return 0;
}
else
return -1;
}
#endif
TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
{
UNREFERENCED_STDARGS;
if (type == 1)
return JNI_TRUE;
#if defined(__linux__)
else if (type == 5)
return JNI_TRUE;
#endif
#if defined(sun)
else if (type == 6)
return JNI_TRUE;
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
else if (type == 7)
return JNI_TRUE;
#endif
else
return JNI_FALSE;
}
TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
jlongArray inf)
{
jint rv;
int i;
jsize ilen = (*e)->GetArrayLength(e, inf);
jlong *pvals = (*e)->GetLongArrayElements(e, inf, NULL);
UNREFERENCED(o);
if (ilen < 16) {
return APR_EINVAL;
}
for (i = 0; i < 16; i++)
pvals[i] = 0;
#if defined(__linux__)
{
struct sysinfo info;
if (sysinfo(&info))
rv = apr_get_os_error();
else {
pvals[0] = (jlong)(info.totalram * info.mem_unit);
pvals[1] = (jlong)(info.freeram * info.mem_unit);
pvals[2] = (jlong)(info.totalswap * info.mem_unit);
pvals[3] = (jlong)(info.freeswap * info.mem_unit);
pvals[4] = (jlong)(info.sharedram * info.mem_unit);
pvals[5] = (jlong)(info.bufferram * info.mem_unit);
pvals[6] = (jlong)(100 - (info.freeram * 100 / info.totalram));
rv = APR_SUCCESS;
}
}
#elif defined(sun)
{
/* static variables with basic procfs info */
static long creation = 0; /* unix timestamp of process creation */
static int psinf_fd = 0; /* file descriptor for the psinfo procfs file */
static int prusg_fd = 0; /* file descriptor for the usage procfs file */
static size_t rss = 0; /* maximum of resident set size from previous calls */
/* static variables with basic kstat info */
static kstat_ctl_t *kstat_ctl = NULL; /* kstat control object, only initialized once */
static kstat_t *kstat_cpu[MAX_CPUS]; /* array of kstat objects for per cpu statistics */
static int cpu_count = 0; /* number of cpu structures found in kstat */
static kid_t kid = 0; /* kstat ID, for which the kstat_ctl holds the correct chain */
/* non-static variables - general use */
int res = 0; /* general result state */
/* non-static variables - sysinfo/swapctl use */
long ret_sysconf; /* value returned from sysconf call */
long tck_dividend; /* factor used by transforming tick numbers to milliseconds */
long tck_divisor; /* divisor used by transforming tick numbers to milliseconds */
long sys_pagesize = sysconf(_SC_PAGESIZE); /* size of a system memory page in bytes */
long sys_clk_tck = sysconf(_SC_CLK_TCK); /* number of system ticks per second */
struct anoninfo info; /* structure for information about sizes in anonymous memory system */
/* non-static variables - procfs use */
psinfo_t psinf; /* psinfo structure from procfs */
prusage_t prusg; /* usage structure from procfs */
size_t new_rss = 0; /* resident set size read from procfs */
time_t now; /* time needed for calculating process creation time */
/* non-static variables - kstat use */
kstat_t *kstat = NULL; /* kstat working pointer */
cpu_sysinfo_t cpu; /* cpu sysinfo working pointer */
kid_t new_kid = 0; /* kstat ID returned from chain update */
int new_kstat = 0; /* flag indicating, if kstat structure has changed since last call */
rv = APR_SUCCESS;
if (sys_pagesize <= 0) {
rv = apr_get_os_error();
}
else {
ret_sysconf = sysconf(_SC_PHYS_PAGES);
if (ret_sysconf >= 0) {
pvals[0] = (jlong)((jlong)sys_pagesize * ret_sysconf);
}
else {
rv = apr_get_os_error();
}
ret_sysconf = sysconf(_SC_AVPHYS_PAGES);
if (ret_sysconf >= 0) {
pvals[1] = (jlong)((jlong)sys_pagesize * ret_sysconf);
}
else {
rv = apr_get_os_error();
}
res=swapctl(SC_AINFO, &info);
if (res >= 0) {
pvals[2] = (jlong)((jlong)sys_pagesize * info.ani_max);
pvals[3] = (jlong)((jlong)sys_pagesize * info.ani_free);
pvals[6] = (jlong)(100 - (jlong)info.ani_free * 100 / info.ani_max);
}
else {
rv = apr_get_os_error();
}
}
if (psinf_fd == 0) {
psinf_fd = proc_open("psinfo");
}
res = proc_read(&psinf, PSINFO_T_SZ, psinf_fd);
if (res >= 0) {
new_rss = psinf.pr_rssize*1024;
pvals[13] = (jlong)(new_rss);
if (new_rss > rss) {
rss = new_rss;
}
pvals[14] = (jlong)(rss);
}
else {
psinf_fd = 0;
rv = apr_get_os_error();
}
if (prusg_fd == 0) {
prusg_fd = proc_open("usage");
}
res = proc_read(&prusg, PRUSAGE_T_SZ, prusg_fd);
if (res >= 0) {
if (creation <= 0) {
time(&now);
creation = (long)(now - (prusg.pr_tstamp.tv_sec -
prusg.pr_create.tv_sec));
}
pvals[10] = (jlong)(creation);
pvals[11] = (jlong)((jlong)prusg.pr_stime.tv_sec * 1000 +
(prusg.pr_stime.tv_nsec / 1000000));
pvals[12] = (jlong)((jlong)prusg.pr_utime.tv_sec * 1000 +
(prusg.pr_utime.tv_nsec / 1000000));
pvals[15] = (jlong)(prusg.pr_majf);
}
else {
prusg_fd = 0;
rv = apr_get_os_error();
}
if (sys_clk_tck <= 0) {
rv = apr_get_os_error();
}
else {
tck_dividend = 1000;
tck_divisor = sys_clk_tck;
for (i = 0; i < 3; i++) {
if (tck_divisor % 2 == 0) {
tck_divisor = tck_divisor / 2;
tck_dividend = tck_dividend / 2;
}
if (tck_divisor % 5 == 0) {
tck_divisor = tck_divisor / 5;
tck_dividend = tck_dividend / 5;
}
}
if (kstat_ctl == NULL) {
kstat_ctl = kstat_open();
kid = kstat_ctl->kc_chain_id;
new_kstat = 1;
} else {
new_kid = kstat_chain_update(kstat_ctl);
if (new_kid < 0) {
res=kstat_close(kstat_ctl);
kstat_ctl = kstat_open();
kid = kstat_ctl->kc_chain_id;
new_kstat = 1;
} else if (new_kid > 0 && kid != new_kid) {
kid = new_kid;
new_kstat = 1;
}
}
if (new_kstat) {
cpu_count = 0;
for (kstat = kstat_ctl->kc_chain; kstat; kstat = kstat->ks_next) {
if (strncmp(kstat->ks_name, "cpu_stat", 8) == 0) {
kstat_cpu[cpu_count++]=kstat;
}
}
}
for (i = 0; i < cpu_count; i++) {
new_kid = kstat_read(kstat_ctl, kstat_cpu[i], NULL);
if (new_kid >= 0) {
cpu = ((cpu_stat_t *)kstat_cpu[i]->ks_data)->cpu_sysinfo;
if ( tck_divisor == 1 ) {
pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend);
pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend);
pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend);
pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend);
} else {
pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend / tck_divisor);
pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend / tck_divisor);
pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend / tck_divisor);
pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend / tck_divisor);
}
}
}
}
/*
* The next two are not implemented yet for Solaris
* inf[4] - Amount of shared memory
* inf[5] - Memory used by buffers
*
*/
}
#elif defined(DARWIN)
uint64_t mem_total;
size_t len = sizeof(mem_total);
vm_statistics_data_t vm_info;
mach_msg_type_number_t info_count = HOST_VM_INFO_COUNT;
sysctlbyname("hw.memsize", &mem_total, &len, NULL, 0);
pvals[0] = (jlong)mem_total;
host_statistics(mach_host_self (), HOST_VM_INFO, (host_info_t)&vm_info, &info_count);
pvals[1] = (jlong)(((double)vm_info.free_count)*vm_page_size);
pvals[6] = (jlong)(100 - (pvals[1] * 100 / mem_total));
rv = APR_SUCCESS;
/* DARWIN */
#else
rv = APR_ENOTIMPL;
#endif
(*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
return rv;
}
#define LOG_MSG_DOMAIN "Native"
TCN_IMPLEMENT_CALL(jstring, OS, expand)(TCN_STDARGS, jstring val)
{
jstring str;
TCN_ALLOC_CSTRING(val);
UNREFERENCED(o);
/* TODO: Make ${ENVAR} expansion */
str = (*e)->NewStringUTF(e, J2S(val));
TCN_FREE_CSTRING(val);
return str;
}
TCN_IMPLEMENT_CALL(void, OS, sysloginit)(TCN_STDARGS, jstring domain)
{
const char *d;
TCN_ALLOC_CSTRING(domain);
UNREFERENCED(o);
if ((d = J2S(domain)) == NULL)
d = LOG_MSG_DOMAIN;
openlog(d, LOG_CONS | LOG_PID, LOG_LOCAL0);
TCN_FREE_CSTRING(domain);
}
TCN_IMPLEMENT_CALL(void, OS, syslog)(TCN_STDARGS, jint level,
jstring msg)
{
TCN_ALLOC_CSTRING(msg);
int id = LOG_DEBUG;
UNREFERENCED(o);
switch (level) {
case TCN_LOG_EMERG:
id = LOG_EMERG;
break;
case TCN_LOG_ERROR:
id = LOG_ERR;
break;
case TCN_LOG_NOTICE:
id = LOG_NOTICE;
break;
case TCN_LOG_WARN:
id = LOG_WARN;
break;
case TCN_LOG_INFO:
id = LOG_INFO;
break;
}
syslog (id, "%s", J2S(msg));
TCN_FREE_CSTRING(msg);
}