xref: /titanic_44/usr/src/cmd/pools/poold/poold.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
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 2004 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 /*
30  * poold - dynamically adjust pool configuration according to load.
31  */
32 #include <errno.h>
33 #include <jni.h>
34 #include <libintl.h>
35 #include <limits.h>
36 #include <link.h>
37 #include <locale.h>
38 #include <poll.h>
39 #include <pool.h>
40 #include <priv.h>
41 #include <pthread.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <syslog.h>
47 #include <unistd.h>
48 
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <sys/ucontext.h>
52 #include "utils.h"
53 
54 #define	POOLD_DEF_CLASSPATH	"/usr/lib/pool/JPool.jar"
55 #define	POOLD_DEF_LIBPATH	"/usr/lib/pool"
56 
57 #if defined(sparc)
58 #define	PLAT	"sparc"
59 #else
60 #if defined(i386)
61 #define	PLAT	"i386"
62 #else
63 #error Unrecognized platform.
64 #endif
65 #endif
66 
67 #define	PID_PROPERTY_NAME	"system.poold.pid"
68 
69 #define	CLASS_FIELD_DESC(class_desc)	"L" class_desc ";"
70 
71 #define	LEVEL_CLASS_DESC	"java/util/logging/Level"
72 #define	POOLD_CLASS_DESC	"com/sun/solaris/domain/pools/Poold"
73 #define	SEVERITY_CLASS_DESC	"com/sun/solaris/service/logging/Severity"
74 #define	STRING_CLASS_DESC	"java/lang/String"
75 #define	SYSTEM_CLASS_DESC	"java/lang/System"
76 #define	LOGGER_CLASS_DESC	"java/util/logging/Logger"
77 
78 extern char *optarg;
79 
80 static const char *pname;
81 
82 static enum {
83 	LD_TERMINAL = 1,
84 	LD_SYSLOG,
85 	LD_JAVA
86 } log_dest = LD_SYSLOG;
87 
88 typedef enum {
89 	PGAS_GET_ONLY = 1,
90 	PGAS_GET_AND_SET
91 } pgas_mode_t;
92 
93 static const char PNAME_FMT[] = "%s: ";
94 static const char ERRNO_FMT[] = ": %s";
95 
96 static JavaVM *jvm;
97 static int lflag;
98 
99 static jmethodID log_mid;
100 static jobject severity_err;
101 static jobject severity_notice;
102 static jobject base_log;
103 static jclass poold_class;
104 static jobject poold_instance;
105 static int instance_running;
106 static pthread_mutex_t instance_running_lock = PTHREAD_MUTEX_INITIALIZER;
107 
108 static sigset_t hdl_set;
109 
110 static void
111 usage(void)
112 {
113 	(void) fprintf(stderr, gettext("Usage:\t%s [-l <level>]\n"), pname);
114 
115 	exit(E_USAGE);
116 }
117 
118 static void
119 pu_output(int severity, const char *fmt, va_list alist)
120 {
121 	int err = errno;
122 	char line[255] = "";
123 	jobject jseverity;
124 	jobject jline;
125 	JNIEnv *env;
126 	int detach_required = 0;
127 	if (pname != NULL && log_dest == LD_TERMINAL)
128 		(void) snprintf(line, sizeof (line), gettext(PNAME_FMT), pname);
129 
130 	(void) vsnprintf(line + strlen(line), sizeof (line) - strlen(line),
131 	    fmt, alist);
132 
133 	if (line[strlen(line) - 1] != '\n')
134 		(void) snprintf(line + strlen(line), sizeof (line) -
135 		    strlen(line), gettext(ERRNO_FMT), strerror(err));
136 	else
137 		line[strlen(line) - 1] = 0;
138 
139 	switch (log_dest) {
140 	case LD_TERMINAL:
141 		(void) fprintf(stderr, "%s\n", line);
142 		(void) fflush(stderr);
143 		break;
144 	case LD_SYSLOG:
145 		syslog(LOG_ERR, "%s", line);
146 		break;
147 	case LD_JAVA:
148 		if (severity == LOG_ERR)
149 			jseverity = severity_err;
150 		else
151 			jseverity = severity_notice;
152 
153 		if (jvm) {
154 			(*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2);
155 			if (env == NULL) {
156 				detach_required = 1;
157 				(*jvm)->AttachCurrentThread(jvm,
158 				    (void **)&env, NULL);
159 			}
160 			if ((jline = (*env)->NewStringUTF(env, line)) != NULL)
161 				(*env)->CallVoidMethod(env, base_log, log_mid,
162 				    jseverity, jline);
163 			if (detach_required)
164 				(*jvm)->DetachCurrentThread(jvm);
165 		}
166 	}
167 }
168 
169 /*PRINTFLIKE1*/
170 static void
171 pu_notice(const char *fmt, ...)
172 {
173 	va_list alist;
174 	va_start(alist, fmt);
175 	pu_output(LOG_NOTICE, fmt, alist);
176 	va_end(alist);
177 }
178 
179 /*PRINTFLIKE1*/
180 static void
181 pu_die(const char *fmt, ...)
182 {
183 	va_list alist;
184 	va_start(alist, fmt);
185 	pu_output(LOG_ERR, fmt, alist);
186 	va_end(alist);
187 	exit(E_ERROR);
188 }
189 
190 /*
191  * Update the "system.poold.pid" to reflect this instance of poold only
192  * if the property hasn't been set already to reflect an existing
193  * process, and mode is not set to PGAS_GET_ONLY.  Returns the
194  * property's pre-existing value, or -1 otherwise.
195  */
196 static pid_t
197 poold_get_and_set_pid(pgas_mode_t mode)
198 {
199 	pool_conf_t *conf;
200 	pool_elem_t *pe;
201 	pool_value_t *val;
202 	int64_t ival;
203 
204 	if (!(conf = pool_conf_alloc()))
205 		return ((pid_t)-1);
206 
207 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDWR) != 0) {
208 		(void) pool_conf_free(conf);
209 		return ((pid_t)-1);
210 	}
211 
212 	pe = pool_conf_to_elem(conf);
213 	if (!(val = pool_value_alloc())) {
214 		(void) pool_conf_close(conf);
215 		return ((pid_t)-1);
216 	}
217 
218 	if (pool_get_property(conf, pe, PID_PROPERTY_NAME, val) == POC_INT) {
219 		if (pool_value_get_int64(val, &ival) != 0) {
220 			(void) pool_value_free(val);
221 			(void) pool_conf_close(conf);
222 			return ((pid_t)-1);
223 		}
224 	} else {
225 		ival = (pid_t)-1;
226 	}
227 
228 	if (mode == PGAS_GET_AND_SET) {
229 		ival = getpid();
230 		pool_value_set_int64(val, ival);
231 		(void) pool_put_property(conf, pe, PID_PROPERTY_NAME, val);
232 		(void) pool_conf_commit(conf, 0);
233 	}
234 
235 	(void) pool_value_free(val);
236 	(void) pool_conf_close(conf);
237 	pool_conf_free(conf);
238 
239 	return ((pid_t)ival);
240 }
241 
242 /*
243  * Reconfigure the JVM by simply updating a dummy property on the
244  * system element to force pool_conf_update() to detect a change.
245  */
246 static void
247 reconfigure()
248 {
249 	JNIEnv *env;
250 	pool_conf_t *conf;
251 	pool_elem_t *pe;
252 	pool_value_t *val;
253 	const char *err_desc;
254 	int detach_required = 0;
255 
256 	if ((conf = pool_conf_alloc()) == NULL) {
257 		err_desc = pool_strerror(pool_error());
258 		goto destroy;
259 	}
260 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDWR) != 0) {
261 		err_desc = pool_strerror(pool_error());
262 		pool_conf_free(conf);
263 		goto destroy;
264 	}
265 
266 	if ((val = pool_value_alloc()) == NULL) {
267 		err_desc = pool_strerror(pool_error());
268 		(void) pool_conf_close(conf);
269 		pool_conf_free(conf);
270 		goto destroy;
271 	}
272 	pe = pool_conf_to_elem(conf);
273 	pool_value_set_bool(val, 1);
274 	if (pool_put_property(conf, pe, "system.poold.sighup", val) !=
275 	    PO_SUCCESS) {
276 		err_desc = pool_strerror(pool_error());
277 		pool_value_free(val);
278 		(void) pool_conf_close(conf);
279 		pool_conf_free(conf);
280 		goto destroy;
281 	}
282 	pool_value_free(val);
283 	(void) pool_rm_property(conf, pe, "system.poold.sighup");
284 	if (pool_conf_commit(conf, 0) != PO_SUCCESS) {
285 		err_desc = pool_strerror(pool_error());
286 		(void) pool_conf_close(conf);
287 		pool_conf_free(conf);
288 		goto destroy;
289 	}
290 	(void) pool_conf_close(conf);
291 	pool_conf_free(conf);
292 	return;
293 destroy:
294 	if (jvm) {
295 		(*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2);
296 		if (env == NULL) {
297 			detach_required = 1;
298 			(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
299 		}
300 		if (lflag && (*env)->ExceptionOccurred(env))
301 			(*env)->ExceptionDescribe(env);
302 		if (detach_required)
303 			(*jvm)->DetachCurrentThread(jvm);
304 		(*jvm)->DestroyJavaVM(jvm);
305 	}
306 	pu_die(err_desc);
307 }
308 
309 /*
310  * If SIGHUP is invoked, we should just re-initialize poold. Since
311  * there is no easy way to determine when it's safe to re-initialzie
312  * poold, simply update a dummy property on the system element to
313  * force pool_conf_update() to detect a change.
314  *
315  * Both SIGTERM and SIGINT are interpreted as instructions to
316  * shutdown.
317  */
318 /*ARGSUSED*/
319 static void *
320 handle_sig(void *arg)
321 {
322 	for (;;) {
323 		JNIEnv *env;
324 		jmethodID poold_shutdown_mid;
325 		int sig;
326 		char buf[SIG2STR_MAX];
327 		int detach_required = 0;
328 
329 		if ((sig = sigwait(&hdl_set)) < 0)
330 			pu_die("unexpected error: %d\n", errno);
331 		(void) sig2str(sig, buf);
332 		switch (sig) {
333 		case SIGHUP:
334 			reconfigure();
335 			break;
336 		case SIGINT:
337 		case SIGTERM:
338 			(void) pthread_mutex_lock(&instance_running_lock);
339 			if (instance_running) {
340 				(void) pthread_mutex_unlock(
341 				    &instance_running_lock);
342 				(*jvm)->GetEnv(jvm, (void **)&env,
343 				    JNI_VERSION_1_2);
344 				if (env == NULL) {
345 					detach_required = 1;
346 					(*jvm)->AttachCurrentThread(jvm,
347 					    (void **)&env, NULL);
348 				}
349 				pu_notice("terminating due to signal: SIG%s\n",
350 				    buf);
351 				if ((poold_shutdown_mid = (*env)->GetMethodID(
352 				    env, poold_class, "shutdown", "()V")) !=
353 				    NULL) {
354 					(*env)->CallVoidMethod(env,
355 					    poold_instance,
356 					    poold_shutdown_mid);
357 				} else {
358 					(*env)->ExceptionDescribe(env);
359 					pu_die("could not invoke"
360 					    " proper shutdown\n");
361 				}
362 				if (detach_required)
363 					(*jvm)->DetachCurrentThread(jvm);
364 			} else {
365 				(void) pthread_mutex_unlock(
366 				    &instance_running_lock);
367 				pu_die("terminated with signal: SIG%s\n", buf);
368 				/*NOTREACHED*/
369 			}
370 			break;
371 		default:
372 			pu_die("unexpected signal: SIG%s\n", buf);
373 		}
374 	}
375 	/*NOTREACHED*/
376 	return (NULL);
377 }
378 
379 static const char *
380 pu_getpname(const char *arg0)
381 {
382 	char *p;
383 
384 	/*
385 	 * Guard against '/' at end of command invocation.
386 	 */
387 	for (;;) {
388 		p = strrchr(arg0, '/');
389 		if (p == NULL) {
390 			pname = arg0;
391 			break;
392 		} else {
393 			if (*(p + 1) == '\0') {
394 				*p = '\0';
395 				continue;
396 			}
397 
398 			pname = p + 1;
399 			break;
400 		}
401 	}
402 
403 	return (pname);
404 }
405 
406 int
407 main(int argc, char *argv[])
408 {
409 	char c;
410 	char log_severity[16] = "";
411 	pid_t pid;
412 	JavaVMInitArgs vm_args;
413 	JavaVMOption vm_opts[5];
414 	int nopts = 0;
415 	const char *classpath;
416 	const char *libpath;
417 	size_t len;
418 	const char *err_desc;
419 	JNIEnv *env;
420 	jmethodID poold_getinstancewcl_mid;
421 	jmethodID poold_run_mid;
422 	jobject log_severity_string = NULL;
423 	jobject log_severity_obj = NULL;
424 	jclass severity_class;
425 	jmethodID severity_cons_mid;
426 	jfieldID base_log_fid;
427 	int explain_ex = 1;
428 	JavaVM *jvm_tmp;
429 	pthread_t hdl_thread;
430 
431 	pname = pu_getpname(argv[0]);
432 	openlog(pname, 0, LOG_DAEMON);
433 	(void) chdir("/");
434 
435 	(void) setlocale(LC_ALL, "");
436 #if !defined(TEXT_DOMAIN)		/* Should be defined with cc -D. */
437 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't. */
438 #endif
439 	(void) textdomain(TEXT_DOMAIN);
440 
441 	opterr = 0;
442 	while ((c = getopt(argc, argv, "l:P")) != EOF) {
443 		switch (c) {
444 		case 'l':	/* -l option */
445 			lflag++;
446 			(void) strlcpy(log_severity, optarg,
447 			    sizeof (log_severity));
448 			log_dest = LD_TERMINAL;
449 			break;
450 		default:
451 			usage();
452 			/*NOTREACHED*/
453 		}
454 	}
455 
456 	/*
457 	 * Verify no other poold is running.  This condition is checked
458 	 * again later, but should be checked now since it is more
459 	 * serious (i.e.  should be reported before) than a lack of
460 	 * privileges.
461 	 */
462 	if (((pid = poold_get_and_set_pid(PGAS_GET_ONLY)) != (pid_t)-1) &&
463 	    pid != getpid() && kill(pid, 0) == 0)
464 		pu_die(gettext("poold is already active (process %ld)\n"), pid);
465 
466 	/*
467 	 * Check permission
468 	 */
469 	if (!priv_ineffect(PRIV_SYS_RES_CONFIG))
470 		pu_die(gettext(ERR_PRIVILEGE), PRIV_SYS_RES_CONFIG);
471 
472 	/*
473 	 * Establish the classpath and LD_LIBRARY_PATH for native
474 	 * methods, and get the interpreter going.
475 	 */
476 	if ((classpath = getenv("POOLD_CLASSPATH")) == NULL) {
477 		classpath = POOLD_DEF_CLASSPATH;
478 	} else {
479 		const char *cur = classpath;
480 
481 		/*
482 		 * Check the components to make sure they're absolute
483 		 * paths.
484 		 */
485 		while (cur != NULL && *cur) {
486 			if (*cur != '/')
487 				pu_die(gettext(
488 				    "POOLD_CLASSPATH must contain absolute "
489 				    "components\n"));
490 			cur = strchr(cur + 1, ':');
491 		}
492 	}
493 	vm_opts[nopts].optionString = malloc(len = strlen(classpath) +
494 	    strlen("-Djava.class.path=") + 1);
495 	(void) strlcpy(vm_opts[nopts].optionString, "-Djava.class.path=", len);
496 	(void) strlcat(vm_opts[nopts++].optionString, classpath, len);
497 
498 	if ((libpath = getenv("POOLD_LD_LIBRARY_PATH")) == NULL)
499 		libpath = POOLD_DEF_LIBPATH;
500 	vm_opts[nopts].optionString = malloc(len = strlen(libpath) +
501 	    strlen("-Djava.library.path=") + 1);
502 	(void) strlcpy(vm_opts[nopts].optionString, "-Djava.library.path=",
503 	    len);
504 	(void) strlcat(vm_opts[nopts++].optionString, libpath, len);
505 
506 	vm_opts[nopts++].optionString = "-Xrs";
507 	vm_opts[nopts++].optionString = "-enableassertions";
508 
509 	vm_args.options = vm_opts;
510 	vm_args.nOptions = nopts;
511 	vm_args.ignoreUnrecognized = JNI_FALSE;
512 	vm_args.version = 0x00010002;
513 
514 	/*
515 	 * XXX - Forking after the VM is created is desirable to
516 	 * guarantee reporting of errors, but cannot be done (see
517 	 * 4919246).
518 	 *
519 	 * If invoked by libpool(3LIB), it's set the system.poold.pid
520 	 * property and forked already.  If invoked directly and -l is
521 	 * specified, forking is not desired.
522 	 */
523 	if (!lflag && pid != getpid())
524 		switch (fork()) {
525 		case 0:
526 			(void) setsid();
527 			(void) fclose(stdin);
528 			(void) fclose(stdout);
529 			(void) fclose(stderr);
530 			break;
531 		case -1:
532 			pu_die(gettext("cannot fork"));
533 			/*NOTREACHED*/
534 		default:
535 			return (E_PO_SUCCESS);
536 		}
537 
538 	/*
539 	 * In order to avoid problems with arbitrary thread selection
540 	 * when handling asynchronous signals, dedicate a thread to
541 	 * look after these signals.
542 	 */
543 	if (sigemptyset(&hdl_set) < 0 ||
544 	    sigaddset(&hdl_set, SIGHUP) < 0 ||
545 	    sigaddset(&hdl_set, SIGTERM) < 0 ||
546 	    sigaddset(&hdl_set, SIGINT) < 0 ||
547 	    pthread_sigmask(SIG_BLOCK, &hdl_set, NULL) ||
548 	    pthread_create(&hdl_thread, NULL, handle_sig, NULL))
549 		pu_die(gettext("can't install signal handler"));
550 
551 	/*
552 	 * Use jvm_tmp when creating the jvm to prevent race
553 	 * conditions with signal handlers. As soon as the call
554 	 * returns, assign the global jvm to jvm_tmp.
555 	 */
556 	if (JNI_CreateJavaVM(&jvm_tmp, (void **)&env, &vm_args) < 0)
557 		pu_die(gettext("can't create Java VM"));
558 	jvm = jvm_tmp;
559 
560 	/*
561 	 * Locate the Poold class and construct an instance.  A side
562 	 * effect of this is that the poold instance's logHelper will be
563 	 * initialized, establishing loggers for logging errors from
564 	 * this point on.  (Note, in the event of an unanticipated
565 	 * exception, poold will invoke die() itself.)
566 	 */
567 	err_desc = gettext("JVM-related error initializing poold\n");
568 	if ((poold_class = (*env)->FindClass(env, POOLD_CLASS_DESC)) == NULL)
569 		goto destroy;
570 	if ((poold_getinstancewcl_mid = (*env)->GetStaticMethodID(env,
571 	    poold_class, "getInstanceWithConsoleLogging", "("
572 	    CLASS_FIELD_DESC(SEVERITY_CLASS_DESC) ")"
573 	    CLASS_FIELD_DESC(POOLD_CLASS_DESC))) == NULL)
574 		goto destroy;
575 	if ((poold_run_mid = (*env)->GetMethodID(env, poold_class, "run",
576 	    "()V")) == NULL)
577 		goto destroy;
578 	if ((severity_class = (*env)->FindClass(env, SEVERITY_CLASS_DESC))
579 	    == NULL)
580 		goto destroy;
581 	if ((severity_cons_mid = (*env)->GetStaticMethodID(env, severity_class,
582 	    "getSeverityWithName", "(" CLASS_FIELD_DESC(STRING_CLASS_DESC) ")"
583 	    CLASS_FIELD_DESC(SEVERITY_CLASS_DESC))) == NULL)
584 		goto destroy;
585 
586 	/*
587 	 * -l <level> was specified, indicating that messages are to be
588 	 * logged to the console only.
589 	 */
590 	if (strlen(log_severity) > 0) {
591 		if ((log_severity_string = (*env)->NewStringUTF(env,
592 		    log_severity)) == NULL)
593 			goto destroy;
594 		if ((log_severity_obj = (*env)->CallStaticObjectMethod(env,
595 		    severity_class, severity_cons_mid, log_severity_string)) ==
596 		    NULL) {
597 			err_desc = gettext("invalid level specified\n");
598 			explain_ex = 0;
599 			goto destroy;
600 		}
601 	} else
602 		log_severity_obj = NULL;
603 
604 	if ((poold_instance = (*env)->CallStaticObjectMethod(env, poold_class,
605 	    poold_getinstancewcl_mid, log_severity_obj)) == NULL)
606 		goto destroy;
607 
608 	/*
609 	 * Grab a global reference to poold for use in our signal
610 	 * handlers.
611 	 */
612 	poold_instance = (*env)->NewGlobalRef(env, poold_instance);
613 
614 	/*
615 	 * Ready LD_JAVA logging.
616 	 */
617 	err_desc = gettext("cannot initialize logging\n");
618 	if ((log_severity_string = (*env)->NewStringUTF(env, "err")) == NULL)
619 		goto destroy;
620 	if (!(severity_err = (*env)->CallStaticObjectMethod(env, severity_class,
621 	    severity_cons_mid, log_severity_string)))
622 		goto destroy;
623 	if (!(severity_err = (*env)->NewGlobalRef(env, severity_err)))
624 		goto destroy;
625 
626 	if ((log_severity_string = (*env)->NewStringUTF(env, "notice")) == NULL)
627 		goto destroy;
628 	if (!(severity_notice = (*env)->CallStaticObjectMethod(env,
629 	    severity_class, severity_cons_mid, log_severity_string)))
630 		goto destroy;
631 	if (!(severity_notice = (*env)->NewGlobalRef(env, severity_notice)))
632 		goto destroy;
633 
634 	if (!(base_log_fid = (*env)->GetStaticFieldID(env, poold_class,
635 	    "BASE_LOG", CLASS_FIELD_DESC(LOGGER_CLASS_DESC))))
636 		goto destroy;
637 	if (!(base_log = (*env)->GetStaticObjectField(env, poold_class,
638 	    base_log_fid)))
639 		goto destroy;
640 	if (!(base_log = (*env)->NewGlobalRef(env, base_log)))
641 		goto destroy;
642 	if (!(log_mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env,
643 	    base_log), "log", "(" CLASS_FIELD_DESC(LEVEL_CLASS_DESC)
644 	    CLASS_FIELD_DESC(STRING_CLASS_DESC) ")V")))
645 		goto destroy;
646 	log_dest = LD_JAVA;
647 
648 	/*
649 	 * Now we're ready to start poold.  Store our pid in the pools
650 	 * configuration to mark that an instance of poold is active,
651 	 * then invoke Poold.run(), which does not normally return.
652 	 *
653 	 * Note that the ignoreUpdates variable in Poold is used to
654 	 * allow Poold to ignore the pools configuration update that
655 	 * this change triggers. If this code is ever modified to
656 	 * remove or modify this logic, then the Poold class must also
657 	 * be modified to keep the actions synchronized.
658 	 */
659 
660 	if (((pid = poold_get_and_set_pid(PGAS_GET_AND_SET)) != (pid_t)-1) &&
661 	    pid != getpid() && kill(pid, 0) == 0)
662 		pu_die(gettext("poold is already active (process %ld)\n"), pid);
663 
664 	(void) pthread_mutex_lock(&instance_running_lock);
665 	instance_running = 1;
666 	(void) pthread_mutex_unlock(&instance_running_lock);
667 	(*env)->CallVoidMethod(env, poold_instance, poold_run_mid);
668 
669 	if ((*env)->ExceptionOccurred(env))
670 		goto destroy;
671 
672 	(*jvm)->DestroyJavaVM(jvm);
673 	return (E_PO_SUCCESS);
674 
675 destroy:
676 	if (lflag && explain_ex && (*env)->ExceptionOccurred(env))
677 		(*env)->ExceptionDescribe(env);
678 	(*jvm)->DestroyJavaVM(jvm);
679 	pu_die(err_desc);
680 }
681