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