xref: /illumos-gate/usr/src/cmd/pools/poold/libjkstat/jkstat.c (revision 797f979d1fe26bfb1cdeb3e7a86ed24c0b654200)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stddef.h>
30 #include <kstat.h>
31 
32 #include "jkstat.h"
33 
34 /*
35  * Class descriptors
36  */
37 #define	DOUBLE_CLASS_DESC	"java/lang/Double"
38 #define	LONG_CLASS_DESC		"java/lang/Long"
39 #define	UI64_CLASS_DESC		"com/sun/solaris/service/pools/UnsignedInt64"
40 #define	HRTIME_CLASS_DESC	"com/sun/solaris/service/pools/HRTime"
41 #define	KSTAT_CLASS_DESC	"com/sun/solaris/service/kstat/Kstat"
42 #define	KSTATCTL_CLASS_DESC	"com/sun/solaris/service/kstat/KstatCtl"
43 #define	KSTAT_READ_EX_CLASS_DESC \
44 	"com/sun/solaris/service/kstat/KstatReadException"
45 #define	KSTAT_TNS_EX_CLASS_DESC	\
46 	"com/sun/solaris/service/kstat/KstatTypeNotSupportedException"
47 #define	THROWABLE_CLASS_DESC	"java/lang/Throwable"
48 
49 #define	CLASS_FIELD_DESC(class_desc)	"L" class_desc ";"
50 
51 /*
52  * Cached class, method, and field IDs.
53  */
54 static jclass doubleclass;
55 static jclass hrtimeclass;
56 static jclass kstatclass;
57 static jclass kstatctlclass;
58 static jclass longclass;
59 static jclass ui64class;
60 static jfieldID kstat_kctl_fieldid;
61 static jfieldID kstat_ksp_fieldid;
62 static jfieldID kstatctl_kctl_fieldid;
63 static jmethodID doublecons_mid;
64 static jmethodID hrtimecons_mid;
65 static jmethodID kstatcons_mid;
66 static jmethodID longcons_mid;
67 static jmethodID ui64cons_mid;
68 
69 static jobject
70 makeUnsignedInt64(JNIEnv *env, uint64_t value)
71 {
72 	jobject valueObj;
73 	jobject byteArray;
74 	jbyte *bytes;
75 	int i;
76 
77 	if (!(byteArray = (*env)->NewByteArray(env, 9)))
78 		return (NULL); /* OutOfMemoryError thrown */
79 	if (!(bytes = (*env)->GetByteArrayElements(env, byteArray, NULL)))
80 		return (NULL); /* OutOfMemoryError thrown */
81 
82 	/*
83 	 * Interpret the uint64_t as a 9-byte big-endian signed quantity
84 	 * suitable for constructing an UnsignedInt64 or BigInteger.
85 	 */
86 	for (i = 8; i >= 1; i--) {
87 		bytes[i] = value & 0xff;
88 		value >>= 8;
89 	}
90 	bytes[0] = 0;
91 	(*env)->ReleaseByteArrayElements(env, byteArray, bytes, 0);
92 
93 	if (!(valueObj = (*env)->NewObject(env, ui64class, ui64cons_mid,
94 	    byteArray)))
95 		return (NULL); /* exception thrown */
96 
97 	return (valueObj);
98 }
99 
100 /*
101  * Return a Long object with the given value.
102  */
103 static jobject
104 makeLong(JNIEnv *env, jlong value)
105 {
106 	jobject valueObj;
107 
108 	if (!(valueObj = (*env)->NewObject(env, longclass, longcons_mid,
109 	    value)))
110 		return (NULL); /* exception thrown */
111 
112 	return (valueObj);
113 }
114 
115 /*
116  * Return a Double object with the given value.
117  */
118 static jobject
119 makeDouble(JNIEnv *env, jdouble value)
120 {
121 	jobject valueObj;
122 
123 	if (!(valueObj = (*env)->NewObject(env, doubleclass, doublecons_mid,
124 	    value)))
125 		return (NULL); /* exception thrown */
126 
127 	return (valueObj);
128 }
129 
130 /*
131  * Returns the kctl_t * from kstat_open(3kstat).
132  */
133 /*ARGSUSED*/
134 JNIEXPORT jlong JNICALL
135 Java_com_sun_solaris_service_kstat_KstatCtl_open(JNIEnv *env, jobject obj)
136 {
137 	return ((jlong)(uintptr_t)kstat_open());
138 }
139 
140 /*
141  * Invokes kstat_close(3kstat).
142  */
143 /*ARGSUSED*/
144 JNIEXPORT jint JNICALL
145 Java_com_sun_solaris_service_kstat_KstatCtl_close(JNIEnv *env, jobject obj,
146     jlong kctl)
147 {
148 	if (kctl)
149 		return (kstat_close((kstat_ctl_t *)(uintptr_t)kctl));
150 	else
151 		return (0);
152 }
153 
154 /*
155  * Invoke kstat_read(3kstat) for the given Kstat object.
156  */
157 JNIEXPORT void JNICALL Java_com_sun_solaris_service_kstat_Kstat_read(
158     JNIEnv *env, jobject obj)
159 {
160 	kstat_ctl_t *kctl =
161 	    ((kstat_ctl_t *)(uintptr_t)(*env)->GetLongField(env, obj,
162 	    kstat_kctl_fieldid));
163 	kstat_t *ksp = ((kstat_t *)(uintptr_t)(*env)->GetLongField(env, obj,
164 	    kstat_ksp_fieldid));
165 	kid_t kid;
166 
167 	if (!ksp || !kctl)
168 		return; /* exception thronw */
169 
170 	kid = kstat_read((kstat_ctl_t *)kctl, (kstat_t *)ksp, NULL);
171 	if (kid == -1) {
172 		jclass e;
173 		if (!(e = (*env)->FindClass(env, KSTAT_READ_EX_CLASS_DESC)))
174 			return; /* exception thrown */
175 
176 		(*env)->Throw(env, (*env)->NewObject(env, e,
177 		    (*env)->GetStaticMethodID(env, e, "<init>",
178 		    "()" CLASS_FIELD_DESC(THROWABLE_CLASS_DESC))));
179 	}
180 }
181 
182 /*
183  * Return a Kstat object corresponding to the result of
184  * kstat_lookup(3kstat).
185  */
186 JNIEXPORT jobject JNICALL
187 Java_com_sun_solaris_service_kstat_KstatCtl_lookup(JNIEnv *env, jobject obj,
188     jstring moduleObj, jint instance, jstring nameObj)
189 {
190 	const char *module = NULL;
191 	const char *name = NULL;
192 	kstat_ctl_t *kctl;
193 	kstat_t *ksp;
194 	jobject kstatObject = NULL;
195 
196 	if (moduleObj == NULL || nameObj == NULL)
197 		return (NULL);
198 
199 	if (!(module = (*env)->GetStringUTFChars(env, moduleObj, NULL)))
200 		goto done; /* exception thrown */
201 	if (!(name = (*env)->GetStringUTFChars(env, nameObj, NULL)))
202 		goto done; /* exception thrown */
203 
204 	kctl = (kstat_ctl_t *)(uintptr_t)(*env)->GetLongField(env, obj,
205 	    kstatctl_kctl_fieldid);
206 	ksp = kstat_lookup(kctl, (char *)module, instance, (char *)name);
207 	if (ksp)
208 		kstatObject = (*env)->NewObject(env, kstatclass, kstatcons_mid,
209 		    (jlong)(uintptr_t)kctl, (jlong)(uintptr_t)ksp);
210 
211 done:
212 	if (name)
213 		(*env)->ReleaseStringUTFChars(env, nameObj, name);
214 	if (module)
215 		(*env)->ReleaseStringUTFChars(env, moduleObj, module);
216 
217 	return (kstatObject);
218 }
219 
220 /*
221  * Returns the named value -- the value of the named kstat, or field in
222  * a raw kstat, as applicable, and available.  Returns <i>null</i> if no
223  * such named kstat or field is available.
224  *
225  * Throws KstatTypeNotSupportedException if the raw kstat is not
226  * understood.  (Presently, none are.)
227  */
228 JNIEXPORT jobject JNICALL
229 Java_com_sun_solaris_service_kstat_Kstat_getValue(JNIEnv *env, jobject obj,
230     jstring nameObj)
231 {
232 	kstat_t *ksp = ((kstat_t *)(uintptr_t)(*env)->GetLongField(env, obj,
233 	    kstat_ksp_fieldid));
234 	jobject valueObj = NULL;
235 	kstat_named_t *ksnp;
236 	const char *name;
237 	jclass exceptionClass;
238 
239 	if (!nameObj)
240 		return (NULL);
241 
242 	if (!(name = (*env)->GetStringUTFChars(env, nameObj, NULL)))
243 		return (NULL); /* exception thrown */
244 
245 	if (!(exceptionClass = (*env)->FindClass(env,
246 	    KSTAT_TNS_EX_CLASS_DESC))) {
247 		(*env)->ReleaseStringUTFChars(env, nameObj, name);
248 		return (NULL); /* exception thrown */
249 	}
250 
251 	switch (ksp->ks_type) {
252 	case KSTAT_TYPE_NAMED:
253 		ksnp = kstat_data_lookup(ksp, (char *)name);
254 		if (ksnp == NULL)
255 			break;
256 		switch (ksnp->data_type) {
257 		case KSTAT_DATA_CHAR:
258 			valueObj = makeLong(env, ksnp->value.c[0]);
259 			break;
260 		case KSTAT_DATA_INT32:
261 			valueObj = makeLong(env, ksnp->value.i32);
262 			break;
263 		case KSTAT_DATA_UINT32:
264 			valueObj = makeLong(env, ksnp->value.ui32);
265 			break;
266 		case KSTAT_DATA_INT64:
267 			valueObj = makeLong(env, ksnp->value.i64);
268 			break;
269 		case KSTAT_DATA_UINT64:
270 			valueObj = makeUnsignedInt64(env, ksnp->value.ui64);
271 			break;
272 		case KSTAT_DATA_STRING:
273 			valueObj = (*env)->NewStringUTF(env,
274 			    KSTAT_NAMED_STR_PTR(ksnp));
275 			break;
276 		case KSTAT_DATA_FLOAT:
277 			valueObj = makeDouble(env, ksnp->value.f);
278 			break;
279 		case KSTAT_DATA_DOUBLE:
280 			valueObj = makeDouble(env, ksnp->value.d);
281 			break;
282 		default:
283 			goto fail;
284 		}
285 		break;
286 	default:
287 		goto fail;
288 	}
289 
290 	(*env)->ReleaseStringUTFChars(env, nameObj, name);
291 	return (valueObj);
292 
293 fail:
294 	(*env)->ReleaseStringUTFChars(env, nameObj, name);
295 	(*env)->Throw(env, (*env)->NewObject(env, exceptionClass,
296 	    (*env)->GetStaticMethodID(env, exceptionClass, "<init>",
297 	    "()" CLASS_FIELD_DESC(THROWABLE_CLASS_DESC))));
298 
299 	return (valueObj);
300 }
301 
302 /*
303  * Given a Kstat object, return, as an HRTime object, its kstat_t's
304  * field at the given offset.
305  */
306 static jobject
307 ksobj_get_hrtime(JNIEnv *env, jobject obj, offset_t ksfieldoff)
308 {
309 	kstat_t *ksp = ((kstat_t *)(uintptr_t)(*env)->GetLongField(env, obj,
310 	    kstat_ksp_fieldid));
311 
312 	if (!ksp)
313 		return (NULL); /* exception thrown */
314 
315 	return ((*env)->NewObject(env, hrtimeclass, hrtimecons_mid,
316 	    makeUnsignedInt64(env, *((hrtime_t *)ksp + ksfieldoff *
317 	    sizeof (hrtime_t)))));
318 }
319 
320 /*
321  * Given a Kstat object, return as an HRTime object its ks_snaptime
322  * field.
323  */
324 JNIEXPORT jobject JNICALL
325 Java_com_sun_solaris_service_kstat_Kstat_getSnapTime(JNIEnv *env, jobject obj)
326 {
327 	return (ksobj_get_hrtime(env, obj, offsetof(kstat_t, ks_snaptime)));
328 }
329 
330 /*
331  * Given a Kstat object, return as an HRTime object its ks_crtime
332  * field.
333  */
334 JNIEXPORT jobject JNICALL
335 Java_com_sun_solaris_service_kstat_Kstat_getCreationTime(JNIEnv *env,
336     jobject obj)
337 {
338 	return (ksobj_get_hrtime(env, obj, offsetof(kstat_t, ks_crtime)));
339 }
340 
341 /*
342  * Invoke kstat_chain_update(3kstat) for the kstat chain corresponding
343  * to the given KstatCtl object.
344  */
345 JNIEXPORT void JNICALL
346 Java_com_sun_solaris_service_kstat_KstatCtl_chainUpdate(JNIEnv *env,
347     jobject obj)
348 {
349 	kstat_ctl_t *kctl;
350 
351 	kctl = (kstat_ctl_t *)(uintptr_t)(*env)->GetLongField(env, obj,
352 	    kstatctl_kctl_fieldid);
353 
354 	(void) kstat_chain_update(kctl);
355 }
356 
357 /*
358  * Cache class, method, and field IDs.
359  */
360 /*ARGSUSED*/
361 JNIEXPORT void JNICALL
362 Java_com_sun_solaris_service_kstat_KstatCtl_init(JNIEnv *env, jclass clazz)
363 {
364 	jclass doubleclass_lref;
365 	jclass hrtimeclass_lref;
366 	jclass kstatclass_lref;
367 	jclass kstatctlclass_lref;
368 	jclass longclass_lref;
369 	jclass ui64class_lref;
370 
371 	if (!(doubleclass_lref = (*env)->FindClass(env, DOUBLE_CLASS_DESC)))
372 		return; /* exception thrown */
373 	if (!(doubleclass = (*env)->NewGlobalRef(env, doubleclass_lref)))
374 		return; /* exception thrown */
375 	if (!(doublecons_mid = (*env)->GetMethodID(env, doubleclass, "<init>",
376 	    "(D)V")))
377 		return; /* exception thrown */
378 
379 	if (!(hrtimeclass_lref = (*env)->FindClass(env, HRTIME_CLASS_DESC)))
380 		return; /* exception thrown */
381 	if (!(hrtimeclass = (*env)->NewGlobalRef(env, hrtimeclass_lref)))
382 		return; /* exception thrown */
383 	if (!(hrtimecons_mid = (*env)->GetMethodID(env, hrtimeclass, "<init>",
384 	    "(" CLASS_FIELD_DESC(UI64_CLASS_DESC) ")V")))
385 		return; /* exception thrown */
386 
387 	if (!(kstatclass_lref = (*env)->FindClass(env, KSTAT_CLASS_DESC)))
388 		return; /* exception thrown */
389 	if (!(kstatclass = (*env)->NewGlobalRef(env, kstatclass_lref)))
390 		return; /* exception thrown */
391 	if (!(kstatcons_mid = (*env)->GetMethodID(env, kstatclass, "<init>",
392 	    "(JJ)V")))
393 		return; /* exception thrown */
394 	if (!(kstat_kctl_fieldid = (*env)->GetFieldID(env, kstatclass, "kctl",
395 	    "J")))
396 		return; /* exception thrown */
397 	if (!(kstat_ksp_fieldid = (*env)->GetFieldID(env, kstatclass, "ksp",
398 	    "J")))
399 		return; /* exception thrown */
400 
401 	if (!(kstatctlclass_lref = (*env)->FindClass(env, KSTATCTL_CLASS_DESC)))
402 		return; /* exception thrown */
403 	if (!(kstatctlclass = (*env)->NewGlobalRef(env, kstatctlclass_lref)))
404 		return; /* exception thrown */
405 	if (!(kstatctl_kctl_fieldid = (*env)->GetFieldID(env, kstatctlclass,
406 	    "kctl", "J")))
407 		return; /* exception thrown */
408 
409 	if (!(longclass_lref = (*env)->FindClass(env, LONG_CLASS_DESC)))
410 		return; /* exception thrown */
411 	if (!(longclass = (*env)->NewGlobalRef(env, longclass_lref)))
412 		return; /* exception thrown */
413 	if (!(longcons_mid = (*env)->GetMethodID(env, longclass, "<init>",
414 	    "(J)V")))
415 		return; /* exception thrown */
416 
417 	if (!(ui64class_lref = (*env)->FindClass(env, UI64_CLASS_DESC)))
418 		return; /* exception thrown */
419 	if (!(ui64class = (*env)->NewGlobalRef(env, ui64class_lref)))
420 		return; /* exception thrown */
421 	ui64cons_mid = (*env)->GetMethodID(env, ui64class, "<init>", "([B)V");
422 }
423