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