xref: /titanic_51/usr/src/cmd/pools/poold/poold.c (revision 1500b9a0ea69fcfd5585a2848fc9ce0c378733b9)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*1500b9a0Sgarypen  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * poold - dynamically adjust pool configuration according to load.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <jni.h>
347c478bd9Sstevel@tonic-gate #include <libintl.h>
357c478bd9Sstevel@tonic-gate #include <limits.h>
367c478bd9Sstevel@tonic-gate #include <link.h>
377c478bd9Sstevel@tonic-gate #include <locale.h>
387c478bd9Sstevel@tonic-gate #include <poll.h>
397c478bd9Sstevel@tonic-gate #include <pool.h>
407c478bd9Sstevel@tonic-gate #include <priv.h>
417c478bd9Sstevel@tonic-gate #include <pthread.h>
427c478bd9Sstevel@tonic-gate #include <signal.h>
437c478bd9Sstevel@tonic-gate #include <stdio.h>
447c478bd9Sstevel@tonic-gate #include <stdlib.h>
457c478bd9Sstevel@tonic-gate #include <string.h>
467c478bd9Sstevel@tonic-gate #include <syslog.h>
477c478bd9Sstevel@tonic-gate #include <unistd.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include <sys/stat.h>
507c478bd9Sstevel@tonic-gate #include <sys/types.h>
517c478bd9Sstevel@tonic-gate #include <sys/ucontext.h>
527c478bd9Sstevel@tonic-gate #include "utils.h"
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	POOLD_DEF_CLASSPATH	"/usr/lib/pool/JPool.jar"
557c478bd9Sstevel@tonic-gate #define	POOLD_DEF_LIBPATH	"/usr/lib/pool"
5626d8ba22Sgarypen #define	SMF_SVC_INSTANCE	"svc:/system/pools/dynamic:default"
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #if defined(sparc)
597c478bd9Sstevel@tonic-gate #define	PLAT	"sparc"
607c478bd9Sstevel@tonic-gate #else
617c478bd9Sstevel@tonic-gate #if defined(i386)
627c478bd9Sstevel@tonic-gate #define	PLAT	"i386"
637c478bd9Sstevel@tonic-gate #else
647c478bd9Sstevel@tonic-gate #error Unrecognized platform.
657c478bd9Sstevel@tonic-gate #endif
667c478bd9Sstevel@tonic-gate #endif
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	CLASS_FIELD_DESC(class_desc)	"L" class_desc ";"
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #define	LEVEL_CLASS_DESC	"java/util/logging/Level"
717c478bd9Sstevel@tonic-gate #define	POOLD_CLASS_DESC	"com/sun/solaris/domain/pools/Poold"
727c478bd9Sstevel@tonic-gate #define	SEVERITY_CLASS_DESC	"com/sun/solaris/service/logging/Severity"
737c478bd9Sstevel@tonic-gate #define	STRING_CLASS_DESC	"java/lang/String"
747c478bd9Sstevel@tonic-gate #define	SYSTEM_CLASS_DESC	"java/lang/System"
757c478bd9Sstevel@tonic-gate #define	LOGGER_CLASS_DESC	"java/util/logging/Logger"
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate extern char *optarg;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static const char *pname;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static enum {
827c478bd9Sstevel@tonic-gate 	LD_TERMINAL = 1,
837c478bd9Sstevel@tonic-gate 	LD_SYSLOG,
847c478bd9Sstevel@tonic-gate 	LD_JAVA
857c478bd9Sstevel@tonic-gate } log_dest = LD_SYSLOG;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate static const char PNAME_FMT[] = "%s: ";
887c478bd9Sstevel@tonic-gate static const char ERRNO_FMT[] = ": %s";
897c478bd9Sstevel@tonic-gate 
90*1500b9a0Sgarypen static pthread_mutex_t jvm_lock = PTHREAD_MUTEX_INITIALIZER;
91*1500b9a0Sgarypen static JavaVM *jvm;		/* protected by jvm_lock */
92*1500b9a0Sgarypen static int instance_running;	/* protected by jvm_lock */
93*1500b9a0Sgarypen static int lflag;		/* specifies poold logging mode */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate static jmethodID log_mid;
967c478bd9Sstevel@tonic-gate static jobject severity_err;
977c478bd9Sstevel@tonic-gate static jobject severity_notice;
987c478bd9Sstevel@tonic-gate static jobject base_log;
997c478bd9Sstevel@tonic-gate static jclass poold_class;
1007c478bd9Sstevel@tonic-gate static jobject poold_instance;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static sigset_t hdl_set;
1037c478bd9Sstevel@tonic-gate 
104*1500b9a0Sgarypen static void pu_notice(const char *fmt, ...);
105414388d7Ssl108498 static void pu_die(const char *fmt, ...) __NORETURN;
106414388d7Ssl108498 
1077c478bd9Sstevel@tonic-gate static void
1087c478bd9Sstevel@tonic-gate usage(void)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Usage:\t%s [-l <level>]\n"), pname);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	exit(E_USAGE);
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate static void
116*1500b9a0Sgarypen check_thread_attached(JNIEnv **env)
117*1500b9a0Sgarypen {
118*1500b9a0Sgarypen 	int ret;
119*1500b9a0Sgarypen 
120*1500b9a0Sgarypen 	ret = (*jvm)->GetEnv(jvm, (void **)env, JNI_VERSION_1_4);
121*1500b9a0Sgarypen 	if (*env == NULL) {
122*1500b9a0Sgarypen 		if (ret == JNI_EVERSION) {
123*1500b9a0Sgarypen 			/*
124*1500b9a0Sgarypen 			 * Avoid recursively calling
125*1500b9a0Sgarypen 			 * check_thread_attached()
126*1500b9a0Sgarypen 			 */
127*1500b9a0Sgarypen 			if (log_dest == LD_JAVA)
128*1500b9a0Sgarypen 				log_dest = LD_TERMINAL;
129*1500b9a0Sgarypen 			pu_notice(gettext("incorrect JNI version"));
130*1500b9a0Sgarypen 			exit(E_ERROR);
131*1500b9a0Sgarypen 		}
132*1500b9a0Sgarypen 		if ((*jvm)->AttachCurrentThreadAsDaemon(jvm, (void **)env,
133*1500b9a0Sgarypen 			NULL) != 0) {
134*1500b9a0Sgarypen 			/*
135*1500b9a0Sgarypen 			 * Avoid recursively calling
136*1500b9a0Sgarypen 			 * check_thread_attached()
137*1500b9a0Sgarypen 			 */
138*1500b9a0Sgarypen 			if (log_dest == LD_JAVA)
139*1500b9a0Sgarypen 				log_dest = LD_TERMINAL;
140*1500b9a0Sgarypen 			pu_notice(gettext("thread attach failed"));
141*1500b9a0Sgarypen 			exit(E_ERROR);
142*1500b9a0Sgarypen 		}
143*1500b9a0Sgarypen 	}
144*1500b9a0Sgarypen }
145*1500b9a0Sgarypen 
146*1500b9a0Sgarypen /*
147*1500b9a0Sgarypen  * Output a message to the designated logging destination.
148*1500b9a0Sgarypen  *
149*1500b9a0Sgarypen  * severity - Specified the severity level when using LD_JAVA logging
150*1500b9a0Sgarypen  * fmt - specified the format of the output message
151*1500b9a0Sgarypen  * alist - varargs used in the output message
152*1500b9a0Sgarypen  */
153*1500b9a0Sgarypen static void
1547c478bd9Sstevel@tonic-gate pu_output(int severity, const char *fmt, va_list alist)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	int err = errno;
1577c478bd9Sstevel@tonic-gate 	char line[255] = "";
1587c478bd9Sstevel@tonic-gate 	jobject jseverity;
1597c478bd9Sstevel@tonic-gate 	jobject jline;
160*1500b9a0Sgarypen 	JNIEnv *env = NULL;
161*1500b9a0Sgarypen 
1627c478bd9Sstevel@tonic-gate 	if (pname != NULL && log_dest == LD_TERMINAL)
1637c478bd9Sstevel@tonic-gate 		(void) snprintf(line, sizeof (line), gettext(PNAME_FMT), pname);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	(void) vsnprintf(line + strlen(line), sizeof (line) - strlen(line),
1667c478bd9Sstevel@tonic-gate 	    fmt, alist);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	if (line[strlen(line) - 1] != '\n')
1697c478bd9Sstevel@tonic-gate 		(void) snprintf(line + strlen(line), sizeof (line) -
1707c478bd9Sstevel@tonic-gate 		    strlen(line), gettext(ERRNO_FMT), strerror(err));
1717c478bd9Sstevel@tonic-gate 	else
1727c478bd9Sstevel@tonic-gate 		line[strlen(line) - 1] = 0;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	switch (log_dest) {
1757c478bd9Sstevel@tonic-gate 	case LD_TERMINAL:
1767c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s\n", line);
1777c478bd9Sstevel@tonic-gate 		(void) fflush(stderr);
1787c478bd9Sstevel@tonic-gate 		break;
1797c478bd9Sstevel@tonic-gate 	case LD_SYSLOG:
1807c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "%s", line);
1817c478bd9Sstevel@tonic-gate 		break;
1827c478bd9Sstevel@tonic-gate 	case LD_JAVA:
1837c478bd9Sstevel@tonic-gate 		if (severity == LOG_ERR)
1847c478bd9Sstevel@tonic-gate 			jseverity = severity_err;
1857c478bd9Sstevel@tonic-gate 		else
1867c478bd9Sstevel@tonic-gate 			jseverity = severity_notice;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 		if (jvm) {
189*1500b9a0Sgarypen 			check_thread_attached(&env);
1907c478bd9Sstevel@tonic-gate 			if ((jline = (*env)->NewStringUTF(env, line)) != NULL)
1917c478bd9Sstevel@tonic-gate 				(*env)->CallVoidMethod(env, base_log, log_mid,
1927c478bd9Sstevel@tonic-gate 				    jseverity, jline);
1937c478bd9Sstevel@tonic-gate 		}
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
197*1500b9a0Sgarypen /*
198*1500b9a0Sgarypen  * Notify the user with the supplied message.
199*1500b9a0Sgarypen  */
2007c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
2017c478bd9Sstevel@tonic-gate static void
2027c478bd9Sstevel@tonic-gate pu_notice(const char *fmt, ...)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	va_list alist;
205*1500b9a0Sgarypen 
2067c478bd9Sstevel@tonic-gate 	va_start(alist, fmt);
2077c478bd9Sstevel@tonic-gate 	pu_output(LOG_NOTICE, fmt, alist);
2087c478bd9Sstevel@tonic-gate 	va_end(alist);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
211*1500b9a0Sgarypen /*
212*1500b9a0Sgarypen  * Stop the application executing inside the JVM. Always ensure that jvm_lock
213*1500b9a0Sgarypen  * is held before invoking this function.
214*1500b9a0Sgarypen  */
215*1500b9a0Sgarypen static void
216*1500b9a0Sgarypen halt_application(void)
217*1500b9a0Sgarypen {
218*1500b9a0Sgarypen 	JNIEnv *env = NULL;
219*1500b9a0Sgarypen 	jmethodID poold_shutdown_mid;
220*1500b9a0Sgarypen 
221*1500b9a0Sgarypen 	if (jvm && instance_running) {
222*1500b9a0Sgarypen 		check_thread_attached(&env);
223*1500b9a0Sgarypen 		if ((poold_shutdown_mid = (*env)->GetMethodID(
224*1500b9a0Sgarypen 		    env, poold_class, "shutdown", "()V")) != NULL) {
225*1500b9a0Sgarypen 			(*env)->CallVoidMethod(env, poold_instance,
226*1500b9a0Sgarypen 			    poold_shutdown_mid);
227*1500b9a0Sgarypen 		} else {
228*1500b9a0Sgarypen 			if (lflag && (*env)->ExceptionOccurred(env)) {
229*1500b9a0Sgarypen 				(*env)->ExceptionDescribe(env);
230*1500b9a0Sgarypen 				pu_notice("could not invoke proper shutdown\n");
231*1500b9a0Sgarypen 			}
232*1500b9a0Sgarypen 		}
233*1500b9a0Sgarypen 		instance_running = 0;
234*1500b9a0Sgarypen 	}
235*1500b9a0Sgarypen }
236*1500b9a0Sgarypen 
237*1500b9a0Sgarypen /*
238*1500b9a0Sgarypen  * Warn the user with the supplied error message, halt the application,
239*1500b9a0Sgarypen  * destroy the JVM and then exit the process.
240*1500b9a0Sgarypen  */
2417c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
2427c478bd9Sstevel@tonic-gate static void
2437c478bd9Sstevel@tonic-gate pu_die(const char *fmt, ...)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	va_list alist;
246*1500b9a0Sgarypen 
2477c478bd9Sstevel@tonic-gate 	va_start(alist, fmt);
2487c478bd9Sstevel@tonic-gate 	pu_output(LOG_ERR, fmt, alist);
2497c478bd9Sstevel@tonic-gate 	va_end(alist);
250*1500b9a0Sgarypen 	halt_application();
251*1500b9a0Sgarypen 	if (jvm) {
252*1500b9a0Sgarypen 		(*jvm)->DestroyJavaVM(jvm);
253*1500b9a0Sgarypen 		jvm = NULL;
254*1500b9a0Sgarypen 	}
2557c478bd9Sstevel@tonic-gate 	exit(E_ERROR);
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate /*
259*1500b9a0Sgarypen  * Warn the user with the supplied error message and halt the
260*1500b9a0Sgarypen  * application. This function is very similar to pu_die(). However,
261*1500b9a0Sgarypen  * this function is designed to be called from the signal handling
262*1500b9a0Sgarypen  * routine (handle_sig()) where although we wish to let the user know
263*1500b9a0Sgarypen  * that an error has occurred, we do not wish to destroy the JVM or
264*1500b9a0Sgarypen  * exit the process.
2657c478bd9Sstevel@tonic-gate  */
266*1500b9a0Sgarypen /*PRINTFLIKE1*/
2677c478bd9Sstevel@tonic-gate static void
268*1500b9a0Sgarypen pu_terminate(const char *fmt, ...)
2697c478bd9Sstevel@tonic-gate {
270*1500b9a0Sgarypen 	va_list alist;
2717c478bd9Sstevel@tonic-gate 
272*1500b9a0Sgarypen 	va_start(alist, fmt);
273*1500b9a0Sgarypen 	pu_output(LOG_ERR, fmt, alist);
274*1500b9a0Sgarypen 	va_end(alist);
275*1500b9a0Sgarypen 	halt_application();
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate /*
2797c478bd9Sstevel@tonic-gate  * If SIGHUP is invoked, we should just re-initialize poold. Since
2807c478bd9Sstevel@tonic-gate  * there is no easy way to determine when it's safe to re-initialzie
2817c478bd9Sstevel@tonic-gate  * poold, simply update a dummy property on the system element to
2827c478bd9Sstevel@tonic-gate  * force pool_conf_update() to detect a change.
2837c478bd9Sstevel@tonic-gate  *
2847c478bd9Sstevel@tonic-gate  * Both SIGTERM and SIGINT are interpreted as instructions to
2857c478bd9Sstevel@tonic-gate  * shutdown.
2867c478bd9Sstevel@tonic-gate  */
2877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2887c478bd9Sstevel@tonic-gate static void *
2897c478bd9Sstevel@tonic-gate handle_sig(void *arg)
2907c478bd9Sstevel@tonic-gate {
291*1500b9a0Sgarypen 	pool_conf_t *conf = NULL;
292*1500b9a0Sgarypen 	pool_elem_t *pe;
293*1500b9a0Sgarypen 	pool_value_t *val;
294*1500b9a0Sgarypen 	const char *err_desc;
295*1500b9a0Sgarypen 	int keep_handling = 1;
296*1500b9a0Sgarypen 
297*1500b9a0Sgarypen 	while (keep_handling) {
2987c478bd9Sstevel@tonic-gate 		int sig;
2997c478bd9Sstevel@tonic-gate 		char buf[SIG2STR_MAX];
3007c478bd9Sstevel@tonic-gate 
30126d8ba22Sgarypen 		if ((sig = sigwait(&hdl_set)) < 0) {
30226d8ba22Sgarypen 			/*
30326d8ba22Sgarypen 			 * We used forkall() previously to ensure that
30426d8ba22Sgarypen 			 * all threads started by the JVM are
30526d8ba22Sgarypen 			 * duplicated in the child. Since forkall()
30626d8ba22Sgarypen 			 * can cause blocking system calls to be
30726d8ba22Sgarypen 			 * interrupted, check to see if the errno is
30826d8ba22Sgarypen 			 * EINTR and if it is wait again.
30926d8ba22Sgarypen 			 */
31026d8ba22Sgarypen 			if (errno == EINTR)
311*1500b9a0Sgarypen 				continue;
312*1500b9a0Sgarypen 			(void) pthread_mutex_lock(&jvm_lock);
313*1500b9a0Sgarypen 			pu_terminate("unexpected error: %d\n", errno);
314*1500b9a0Sgarypen 			keep_handling = 0;
315*1500b9a0Sgarypen 		} else
316*1500b9a0Sgarypen 			(void) pthread_mutex_lock(&jvm_lock);
3177c478bd9Sstevel@tonic-gate 		(void) sig2str(sig, buf);
3187c478bd9Sstevel@tonic-gate 		switch (sig) {
3197c478bd9Sstevel@tonic-gate 		case SIGHUP:
320*1500b9a0Sgarypen 			if ((conf = pool_conf_alloc()) == NULL) {
321*1500b9a0Sgarypen 				err_desc = pool_strerror(pool_error());
322*1500b9a0Sgarypen 				goto destroy;
323*1500b9a0Sgarypen 			}
324*1500b9a0Sgarypen 			if (pool_conf_open(conf, pool_dynamic_location(),
325*1500b9a0Sgarypen 			    PO_RDWR) != 0) {
326*1500b9a0Sgarypen 				err_desc = pool_strerror(pool_error());
327*1500b9a0Sgarypen 				goto destroy;
328*1500b9a0Sgarypen 			}
329*1500b9a0Sgarypen 
330*1500b9a0Sgarypen 			if ((val = pool_value_alloc()) == NULL) {
331*1500b9a0Sgarypen 				err_desc = pool_strerror(pool_error());
332*1500b9a0Sgarypen 				goto destroy;
333*1500b9a0Sgarypen 			}
334*1500b9a0Sgarypen 			pe = pool_conf_to_elem(conf);
335*1500b9a0Sgarypen 			pool_value_set_bool(val, 1);
336*1500b9a0Sgarypen 			if (pool_put_property(conf, pe, "system.poold.sighup",
337*1500b9a0Sgarypen 			    val) != PO_SUCCESS) {
338*1500b9a0Sgarypen 				err_desc = pool_strerror(pool_error());
339*1500b9a0Sgarypen 				pool_value_free(val);
340*1500b9a0Sgarypen 				goto destroy;
341*1500b9a0Sgarypen 			}
342*1500b9a0Sgarypen 			pool_value_free(val);
343*1500b9a0Sgarypen 			(void) pool_rm_property(conf, pe,
344*1500b9a0Sgarypen 			    "system.poold.sighup");
345*1500b9a0Sgarypen 			if (pool_conf_commit(conf, 0) != PO_SUCCESS) {
346*1500b9a0Sgarypen 				err_desc = pool_strerror(pool_error());
347*1500b9a0Sgarypen 				goto destroy;
348*1500b9a0Sgarypen 			}
349*1500b9a0Sgarypen 			break;
350*1500b9a0Sgarypen destroy:
351*1500b9a0Sgarypen 			if (conf) {
352*1500b9a0Sgarypen 				(void) pool_conf_close(conf);
353*1500b9a0Sgarypen 				pool_conf_free(conf);
354*1500b9a0Sgarypen 			}
355*1500b9a0Sgarypen 			pu_terminate(err_desc);
356*1500b9a0Sgarypen 			keep_handling = 0;
3577c478bd9Sstevel@tonic-gate 			break;
3587c478bd9Sstevel@tonic-gate 		case SIGINT:
3597c478bd9Sstevel@tonic-gate 		case SIGTERM:
3607c478bd9Sstevel@tonic-gate 		default:
361*1500b9a0Sgarypen 			pu_terminate("terminating due to signal: SIG%s\n", buf);
362*1500b9a0Sgarypen 			keep_handling = 0;
363*1500b9a0Sgarypen 			break;
3647c478bd9Sstevel@tonic-gate 		}
365*1500b9a0Sgarypen 		(void) pthread_mutex_unlock(&jvm_lock);
3667c478bd9Sstevel@tonic-gate 	}
367*1500b9a0Sgarypen 	pthread_exit(NULL);
3687c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3697c478bd9Sstevel@tonic-gate 	return (NULL);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
372*1500b9a0Sgarypen /*
373*1500b9a0Sgarypen  * Return the name of the process
374*1500b9a0Sgarypen  */
3757c478bd9Sstevel@tonic-gate static const char *
3767c478bd9Sstevel@tonic-gate pu_getpname(const char *arg0)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	char *p;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	/*
3817c478bd9Sstevel@tonic-gate 	 * Guard against '/' at end of command invocation.
3827c478bd9Sstevel@tonic-gate 	 */
3837c478bd9Sstevel@tonic-gate 	for (;;) {
3847c478bd9Sstevel@tonic-gate 		p = strrchr(arg0, '/');
3857c478bd9Sstevel@tonic-gate 		if (p == NULL) {
3867c478bd9Sstevel@tonic-gate 			pname = arg0;
3877c478bd9Sstevel@tonic-gate 			break;
3887c478bd9Sstevel@tonic-gate 		} else {
3897c478bd9Sstevel@tonic-gate 			if (*(p + 1) == '\0') {
3907c478bd9Sstevel@tonic-gate 				*p = '\0';
3917c478bd9Sstevel@tonic-gate 				continue;
3927c478bd9Sstevel@tonic-gate 			}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 			pname = p + 1;
3957c478bd9Sstevel@tonic-gate 			break;
3967c478bd9Sstevel@tonic-gate 		}
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	return (pname);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate int
4037c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate 	char c;
4067c478bd9Sstevel@tonic-gate 	char log_severity[16] = "";
4077c478bd9Sstevel@tonic-gate 	JavaVMInitArgs vm_args;
4087c478bd9Sstevel@tonic-gate 	JavaVMOption vm_opts[5];
4097c478bd9Sstevel@tonic-gate 	int nopts = 0;
4107c478bd9Sstevel@tonic-gate 	const char *classpath;
4117c478bd9Sstevel@tonic-gate 	const char *libpath;
4127c478bd9Sstevel@tonic-gate 	size_t len;
4137c478bd9Sstevel@tonic-gate 	const char *err_desc;
4147c478bd9Sstevel@tonic-gate 	JNIEnv *env;
4157c478bd9Sstevel@tonic-gate 	jmethodID poold_getinstancewcl_mid;
4167c478bd9Sstevel@tonic-gate 	jmethodID poold_run_mid;
4177c478bd9Sstevel@tonic-gate 	jobject log_severity_string = NULL;
4187c478bd9Sstevel@tonic-gate 	jobject log_severity_obj = NULL;
4197c478bd9Sstevel@tonic-gate 	jclass severity_class;
4207c478bd9Sstevel@tonic-gate 	jmethodID severity_cons_mid;
4217c478bd9Sstevel@tonic-gate 	jfieldID base_log_fid;
4227c478bd9Sstevel@tonic-gate 	pthread_t hdl_thread;
42326d8ba22Sgarypen 	FILE *p;
4247c478bd9Sstevel@tonic-gate 
425*1500b9a0Sgarypen 	(void) pthread_mutex_lock(&jvm_lock);
4267c478bd9Sstevel@tonic-gate 	pname = pu_getpname(argv[0]);
4277c478bd9Sstevel@tonic-gate 	openlog(pname, 0, LOG_DAEMON);
4287c478bd9Sstevel@tonic-gate 	(void) chdir("/");
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4317c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* Should be defined with cc -D. */
4327c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't. */
4337c478bd9Sstevel@tonic-gate #endif
4347c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	opterr = 0;
4377c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "l:P")) != EOF) {
4387c478bd9Sstevel@tonic-gate 		switch (c) {
4397c478bd9Sstevel@tonic-gate 		case 'l':	/* -l option */
4407c478bd9Sstevel@tonic-gate 			lflag++;
4417c478bd9Sstevel@tonic-gate 			(void) strlcpy(log_severity, optarg,
4427c478bd9Sstevel@tonic-gate 			    sizeof (log_severity));
4437c478bd9Sstevel@tonic-gate 			log_dest = LD_TERMINAL;
4447c478bd9Sstevel@tonic-gate 			break;
4457c478bd9Sstevel@tonic-gate 		default:
4467c478bd9Sstevel@tonic-gate 			usage();
4477c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	/*
4527c478bd9Sstevel@tonic-gate 	 * Check permission
4537c478bd9Sstevel@tonic-gate 	 */
4547c478bd9Sstevel@tonic-gate 	if (!priv_ineffect(PRIV_SYS_RES_CONFIG))
4557c478bd9Sstevel@tonic-gate 		pu_die(gettext(ERR_PRIVILEGE), PRIV_SYS_RES_CONFIG);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	/*
45826d8ba22Sgarypen 	 * In order to avoid problems with arbitrary thread selection
45926d8ba22Sgarypen 	 * when handling asynchronous signals, dedicate a thread to
46026d8ba22Sgarypen 	 * look after these signals.
46126d8ba22Sgarypen 	 */
46226d8ba22Sgarypen 	if (sigemptyset(&hdl_set) < 0 ||
46326d8ba22Sgarypen 	    sigaddset(&hdl_set, SIGHUP) < 0 ||
46426d8ba22Sgarypen 	    sigaddset(&hdl_set, SIGTERM) < 0 ||
46526d8ba22Sgarypen 	    sigaddset(&hdl_set, SIGINT) < 0 ||
46626d8ba22Sgarypen 	    pthread_sigmask(SIG_BLOCK, &hdl_set, NULL) ||
46726d8ba22Sgarypen 	    pthread_create(&hdl_thread, NULL, handle_sig, NULL))
46826d8ba22Sgarypen 		pu_die(gettext("can't install signal handler"));
46926d8ba22Sgarypen 
47026d8ba22Sgarypen 	/*
47126d8ba22Sgarypen 	 * If the -l flag is supplied, terminate the SMF service and
47226d8ba22Sgarypen 	 * run interactively from the command line.
47326d8ba22Sgarypen 	 */
47426d8ba22Sgarypen 	if (lflag) {
47526d8ba22Sgarypen 		char *cmd = "/usr/sbin/svcadm disable -st " SMF_SVC_INSTANCE;
47626d8ba22Sgarypen 
47726d8ba22Sgarypen 		if (getenv("SMF_FMRI") != NULL)
47826d8ba22Sgarypen 			pu_die("-l option illegal: %s\n", SMF_SVC_INSTANCE);
47926d8ba22Sgarypen 		/*
48026d8ba22Sgarypen 		 * Since disabling a service isn't synchronous, use the
48126d8ba22Sgarypen 		 * synchronous option from svcadm to achieve synchronous
48226d8ba22Sgarypen 		 * behaviour.
48326d8ba22Sgarypen 		 * This is not very satisfactory, but since this is only
48426d8ba22Sgarypen 		 * for use in debugging scenarios, it will do until there
48526d8ba22Sgarypen 		 * is a C API to synchronously shutdown a service in SMF.
48626d8ba22Sgarypen 		 */
48726d8ba22Sgarypen 		if ((p = popen(cmd, "w")) == NULL || pclose(p) != 0)
48826d8ba22Sgarypen 			pu_die("could not temporarily disable service: %s\n",
48926d8ba22Sgarypen 			    SMF_SVC_INSTANCE);
49026d8ba22Sgarypen 	} else {
49126d8ba22Sgarypen 		/*
49226d8ba22Sgarypen 		 * Check if we are running as a SMF service. If we
49326d8ba22Sgarypen 		 * aren't, terminate this process after enabling the
49426d8ba22Sgarypen 		 * service.
49526d8ba22Sgarypen 		 */
49626d8ba22Sgarypen 		if (getenv("SMF_FMRI") == NULL) {
49726d8ba22Sgarypen 			char *cmd = "/usr/sbin/svcadm enable -s " \
49826d8ba22Sgarypen 			    SMF_SVC_INSTANCE;
49926d8ba22Sgarypen 			if ((p = popen(cmd, "w")) == NULL || pclose(p) != 0)
50026d8ba22Sgarypen 				pu_die("could not enable "
50126d8ba22Sgarypen 				    "service: %s\n", SMF_SVC_INSTANCE);
50226d8ba22Sgarypen 			return (E_PO_SUCCESS);
50326d8ba22Sgarypen 		}
50426d8ba22Sgarypen 	}
50526d8ba22Sgarypen 
50626d8ba22Sgarypen 	/*
5077c478bd9Sstevel@tonic-gate 	 * Establish the classpath and LD_LIBRARY_PATH for native
5087c478bd9Sstevel@tonic-gate 	 * methods, and get the interpreter going.
5097c478bd9Sstevel@tonic-gate 	 */
5107c478bd9Sstevel@tonic-gate 	if ((classpath = getenv("POOLD_CLASSPATH")) == NULL) {
5117c478bd9Sstevel@tonic-gate 		classpath = POOLD_DEF_CLASSPATH;
5127c478bd9Sstevel@tonic-gate 	} else {
5137c478bd9Sstevel@tonic-gate 		const char *cur = classpath;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 		/*
5167c478bd9Sstevel@tonic-gate 		 * Check the components to make sure they're absolute
5177c478bd9Sstevel@tonic-gate 		 * paths.
5187c478bd9Sstevel@tonic-gate 		 */
5197c478bd9Sstevel@tonic-gate 		while (cur != NULL && *cur) {
5207c478bd9Sstevel@tonic-gate 			if (*cur != '/')
5217c478bd9Sstevel@tonic-gate 				pu_die(gettext(
5227c478bd9Sstevel@tonic-gate 				    "POOLD_CLASSPATH must contain absolute "
5237c478bd9Sstevel@tonic-gate 				    "components\n"));
5247c478bd9Sstevel@tonic-gate 			cur = strchr(cur + 1, ':');
5257c478bd9Sstevel@tonic-gate 		}
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 	vm_opts[nopts].optionString = malloc(len = strlen(classpath) +
5287c478bd9Sstevel@tonic-gate 	    strlen("-Djava.class.path=") + 1);
5297c478bd9Sstevel@tonic-gate 	(void) strlcpy(vm_opts[nopts].optionString, "-Djava.class.path=", len);
5307c478bd9Sstevel@tonic-gate 	(void) strlcat(vm_opts[nopts++].optionString, classpath, len);
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	if ((libpath = getenv("POOLD_LD_LIBRARY_PATH")) == NULL)
5337c478bd9Sstevel@tonic-gate 		libpath = POOLD_DEF_LIBPATH;
5347c478bd9Sstevel@tonic-gate 	vm_opts[nopts].optionString = malloc(len = strlen(libpath) +
5357c478bd9Sstevel@tonic-gate 	    strlen("-Djava.library.path=") + 1);
5367c478bd9Sstevel@tonic-gate 	(void) strlcpy(vm_opts[nopts].optionString, "-Djava.library.path=",
5377c478bd9Sstevel@tonic-gate 	    len);
5387c478bd9Sstevel@tonic-gate 	(void) strlcat(vm_opts[nopts++].optionString, libpath, len);
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	vm_opts[nopts++].optionString = "-Xrs";
5417c478bd9Sstevel@tonic-gate 	vm_opts[nopts++].optionString = "-enableassertions";
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	vm_args.options = vm_opts;
5447c478bd9Sstevel@tonic-gate 	vm_args.nOptions = nopts;
5457c478bd9Sstevel@tonic-gate 	vm_args.ignoreUnrecognized = JNI_FALSE;
5467c478bd9Sstevel@tonic-gate 	vm_args.version = 0x00010002;
5477c478bd9Sstevel@tonic-gate 
548*1500b9a0Sgarypen 	if (JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args) < 0)
5497c478bd9Sstevel@tonic-gate 		pu_die(gettext("can't create Java VM"));
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	/*
5527c478bd9Sstevel@tonic-gate 	 * Locate the Poold class and construct an instance.  A side
5537c478bd9Sstevel@tonic-gate 	 * effect of this is that the poold instance's logHelper will be
5547c478bd9Sstevel@tonic-gate 	 * initialized, establishing loggers for logging errors from
5557c478bd9Sstevel@tonic-gate 	 * this point on.  (Note, in the event of an unanticipated
5567c478bd9Sstevel@tonic-gate 	 * exception, poold will invoke die() itself.)
5577c478bd9Sstevel@tonic-gate 	 */
5587c478bd9Sstevel@tonic-gate 	err_desc = gettext("JVM-related error initializing poold\n");
5597c478bd9Sstevel@tonic-gate 	if ((poold_class = (*env)->FindClass(env, POOLD_CLASS_DESC)) == NULL)
5607c478bd9Sstevel@tonic-gate 		goto destroy;
5617c478bd9Sstevel@tonic-gate 	if ((poold_getinstancewcl_mid = (*env)->GetStaticMethodID(env,
5627c478bd9Sstevel@tonic-gate 	    poold_class, "getInstanceWithConsoleLogging", "("
5637c478bd9Sstevel@tonic-gate 	    CLASS_FIELD_DESC(SEVERITY_CLASS_DESC) ")"
5647c478bd9Sstevel@tonic-gate 	    CLASS_FIELD_DESC(POOLD_CLASS_DESC))) == NULL)
5657c478bd9Sstevel@tonic-gate 		goto destroy;
5667c478bd9Sstevel@tonic-gate 	if ((poold_run_mid = (*env)->GetMethodID(env, poold_class, "run",
5677c478bd9Sstevel@tonic-gate 	    "()V")) == NULL)
5687c478bd9Sstevel@tonic-gate 		goto destroy;
5697c478bd9Sstevel@tonic-gate 	if ((severity_class = (*env)->FindClass(env, SEVERITY_CLASS_DESC))
5707c478bd9Sstevel@tonic-gate 	    == NULL)
5717c478bd9Sstevel@tonic-gate 		goto destroy;
5727c478bd9Sstevel@tonic-gate 	if ((severity_cons_mid = (*env)->GetStaticMethodID(env, severity_class,
5737c478bd9Sstevel@tonic-gate 	    "getSeverityWithName", "(" CLASS_FIELD_DESC(STRING_CLASS_DESC) ")"
5747c478bd9Sstevel@tonic-gate 	    CLASS_FIELD_DESC(SEVERITY_CLASS_DESC))) == NULL)
5757c478bd9Sstevel@tonic-gate 		goto destroy;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	/*
5787c478bd9Sstevel@tonic-gate 	 * -l <level> was specified, indicating that messages are to be
5797c478bd9Sstevel@tonic-gate 	 * logged to the console only.
5807c478bd9Sstevel@tonic-gate 	 */
5817c478bd9Sstevel@tonic-gate 	if (strlen(log_severity) > 0) {
5827c478bd9Sstevel@tonic-gate 		if ((log_severity_string = (*env)->NewStringUTF(env,
5837c478bd9Sstevel@tonic-gate 		    log_severity)) == NULL)
5847c478bd9Sstevel@tonic-gate 			goto destroy;
5857c478bd9Sstevel@tonic-gate 		if ((log_severity_obj = (*env)->CallStaticObjectMethod(env,
5867c478bd9Sstevel@tonic-gate 		    severity_class, severity_cons_mid, log_severity_string)) ==
5877c478bd9Sstevel@tonic-gate 		    NULL) {
5887c478bd9Sstevel@tonic-gate 			err_desc = gettext("invalid level specified\n");
5897c478bd9Sstevel@tonic-gate 			goto destroy;
5907c478bd9Sstevel@tonic-gate 		}
5917c478bd9Sstevel@tonic-gate 	} else
5927c478bd9Sstevel@tonic-gate 		log_severity_obj = NULL;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	if ((poold_instance = (*env)->CallStaticObjectMethod(env, poold_class,
5957c478bd9Sstevel@tonic-gate 	    poold_getinstancewcl_mid, log_severity_obj)) == NULL)
5967c478bd9Sstevel@tonic-gate 		goto destroy;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	/*
5997c478bd9Sstevel@tonic-gate 	 * Grab a global reference to poold for use in our signal
6007c478bd9Sstevel@tonic-gate 	 * handlers.
6017c478bd9Sstevel@tonic-gate 	 */
6027c478bd9Sstevel@tonic-gate 	poold_instance = (*env)->NewGlobalRef(env, poold_instance);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	/*
6057c478bd9Sstevel@tonic-gate 	 * Ready LD_JAVA logging.
6067c478bd9Sstevel@tonic-gate 	 */
6077c478bd9Sstevel@tonic-gate 	err_desc = gettext("cannot initialize logging\n");
6087c478bd9Sstevel@tonic-gate 	if ((log_severity_string = (*env)->NewStringUTF(env, "err")) == NULL)
6097c478bd9Sstevel@tonic-gate 		goto destroy;
6107c478bd9Sstevel@tonic-gate 	if (!(severity_err = (*env)->CallStaticObjectMethod(env, severity_class,
6117c478bd9Sstevel@tonic-gate 	    severity_cons_mid, log_severity_string)))
6127c478bd9Sstevel@tonic-gate 		goto destroy;
6137c478bd9Sstevel@tonic-gate 	if (!(severity_err = (*env)->NewGlobalRef(env, severity_err)))
6147c478bd9Sstevel@tonic-gate 		goto destroy;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if ((log_severity_string = (*env)->NewStringUTF(env, "notice")) == NULL)
6177c478bd9Sstevel@tonic-gate 		goto destroy;
6187c478bd9Sstevel@tonic-gate 	if (!(severity_notice = (*env)->CallStaticObjectMethod(env,
6197c478bd9Sstevel@tonic-gate 	    severity_class, severity_cons_mid, log_severity_string)))
6207c478bd9Sstevel@tonic-gate 		goto destroy;
6217c478bd9Sstevel@tonic-gate 	if (!(severity_notice = (*env)->NewGlobalRef(env, severity_notice)))
6227c478bd9Sstevel@tonic-gate 		goto destroy;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (!(base_log_fid = (*env)->GetStaticFieldID(env, poold_class,
6257c478bd9Sstevel@tonic-gate 	    "BASE_LOG", CLASS_FIELD_DESC(LOGGER_CLASS_DESC))))
6267c478bd9Sstevel@tonic-gate 		goto destroy;
6277c478bd9Sstevel@tonic-gate 	if (!(base_log = (*env)->GetStaticObjectField(env, poold_class,
6287c478bd9Sstevel@tonic-gate 	    base_log_fid)))
6297c478bd9Sstevel@tonic-gate 		goto destroy;
6307c478bd9Sstevel@tonic-gate 	if (!(base_log = (*env)->NewGlobalRef(env, base_log)))
6317c478bd9Sstevel@tonic-gate 		goto destroy;
6327c478bd9Sstevel@tonic-gate 	if (!(log_mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env,
6337c478bd9Sstevel@tonic-gate 	    base_log), "log", "(" CLASS_FIELD_DESC(LEVEL_CLASS_DESC)
6347c478bd9Sstevel@tonic-gate 	    CLASS_FIELD_DESC(STRING_CLASS_DESC) ")V")))
6357c478bd9Sstevel@tonic-gate 		goto destroy;
6367c478bd9Sstevel@tonic-gate 	log_dest = LD_JAVA;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	/*
63926d8ba22Sgarypen 	 * If invoked directly and -l is specified, forking is not
64026d8ba22Sgarypen 	 * desired.
6417c478bd9Sstevel@tonic-gate 	 */
64226d8ba22Sgarypen 	if (!lflag)
64326d8ba22Sgarypen 		switch (forkall()) {
64426d8ba22Sgarypen 		case 0:
64526d8ba22Sgarypen 			(void) setsid();
64626d8ba22Sgarypen 			(void) fclose(stdin);
64726d8ba22Sgarypen 			(void) fclose(stdout);
64826d8ba22Sgarypen 			(void) fclose(stderr);
64926d8ba22Sgarypen 			break;
65026d8ba22Sgarypen 		case -1:
65126d8ba22Sgarypen 			pu_die(gettext("cannot fork"));
65226d8ba22Sgarypen 			/*NOTREACHED*/
65326d8ba22Sgarypen 		default:
65426d8ba22Sgarypen 			return (E_PO_SUCCESS);
65526d8ba22Sgarypen 		}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	instance_running = 1;
658*1500b9a0Sgarypen 	(void) pthread_mutex_unlock(&jvm_lock);
659*1500b9a0Sgarypen 
6607c478bd9Sstevel@tonic-gate 	(*env)->CallVoidMethod(env, poold_instance, poold_run_mid);
6617c478bd9Sstevel@tonic-gate 
662*1500b9a0Sgarypen 	(void) pthread_mutex_lock(&jvm_lock);
663*1500b9a0Sgarypen 	if ((*env)->ExceptionOccurred(env)) {
6647c478bd9Sstevel@tonic-gate 		goto destroy;
665*1500b9a0Sgarypen 	}
666*1500b9a0Sgarypen 	if (jvm) {
6677c478bd9Sstevel@tonic-gate 		(*jvm)->DestroyJavaVM(jvm);
668*1500b9a0Sgarypen 		jvm = NULL;
669*1500b9a0Sgarypen 	}
670*1500b9a0Sgarypen 	(void) pthread_mutex_unlock(&jvm_lock);
6717c478bd9Sstevel@tonic-gate 	return (E_PO_SUCCESS);
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate destroy:
674*1500b9a0Sgarypen 	if (lflag && (*env)->ExceptionOccurred(env))
6757c478bd9Sstevel@tonic-gate 		(*env)->ExceptionDescribe(env);
6767c478bd9Sstevel@tonic-gate 	pu_die(err_desc);
6777c478bd9Sstevel@tonic-gate }
678