poold.c revision 26d8ba2242584067b65160d24193c37cdc83cd55
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* poold - dynamically adjust pool configuration according to load.
*/
#include <errno.h>
#include <jni.h>
#include <libintl.h>
#include <limits.h>
#include <link.h>
#include <locale.h>
#include <poll.h>
#include <pool.h>
#include <priv.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/ucontext.h>
#include "utils.h"
#define POOLD_DEF_CLASSPATH "/usr/lib/pool/JPool.jar"
#define POOLD_DEF_LIBPATH "/usr/lib/pool"
#define SMF_SVC_INSTANCE "svc:/system/pools/dynamic:default"
#if defined(sparc)
#define PLAT "sparc"
#else
#if defined(i386)
#define PLAT "i386"
#else
#endif
#endif
#define LEVEL_CLASS_DESC "java/util/logging/Level"
#define STRING_CLASS_DESC "java/lang/String"
#define SYSTEM_CLASS_DESC "java/lang/System"
#define LOGGER_CLASS_DESC "java/util/logging/Logger"
extern char *optarg;
static const char *pname;
static enum {
LD_TERMINAL = 1,
typedef enum {
PGAS_GET_ONLY = 1,
} pgas_mode_t;
static const char PNAME_FMT[] = "%s: ";
static const char ERRNO_FMT[] = ": %s";
static int lflag;
static jobject severity_err;
static jobject severity_notice;
static jclass poold_class;
static jobject poold_instance;
static int instance_running;
static void
usage(void)
{
}
static void
{
int detach_required = 0;
else
switch (log_dest) {
case LD_TERMINAL:
break;
case LD_SYSLOG:
break;
case LD_JAVA:
else
if (jvm) {
detach_required = 1;
}
if (detach_required)
}
}
}
/*PRINTFLIKE1*/
static void
{
}
/*PRINTFLIKE1*/
static void
{
}
/*
* Reconfigure the JVM by simply updating a dummy property on the
* system element to force pool_conf_update() to detect a change.
*/
static void
{
const char *err_desc;
int detach_required = 0;
goto destroy;
}
goto destroy;
}
(void) pool_conf_close(conf);
goto destroy;
}
PO_SUCCESS) {
(void) pool_conf_close(conf);
goto destroy;
}
(void) pool_conf_close(conf);
goto destroy;
}
(void) pool_conf_close(conf);
return;
if (jvm) {
detach_required = 1;
}
if (detach_required)
}
}
/*
* If SIGHUP is invoked, we should just re-initialize poold. Since
* there is no easy way to determine when it's safe to re-initialzie
* poold, simply update a dummy property on the system element to
* force pool_conf_update() to detect a change.
*
* Both SIGTERM and SIGINT are interpreted as instructions to
* shutdown.
*/
/*ARGSUSED*/
static void *
handle_sig(void *arg)
{
for (;;) {
int sig;
char buf[SIG2STR_MAX];
int detach_required = 0;
/*
* We used forkall() previously to ensure that
* all threads started by the JVM are
* duplicated in the child. Since forkall()
* can cause blocking system calls to be
* interrupted, check to see if the errno is
* EINTR and if it is wait again.
*/
goto retry;
}
switch (sig) {
case SIGHUP:
reconfigure();
break;
case SIGINT:
case SIGTERM:
(void) pthread_mutex_lock(&instance_running_lock);
if (instance_running) {
(void) pthread_mutex_unlock(
detach_required = 1;
}
pu_notice("terminating due to signal: SIG%s\n",
buf);
NULL) {
} else {
pu_die("could not invoke"
" proper shutdown\n");
}
if (detach_required)
} else {
(void) pthread_mutex_unlock(
/*NOTREACHED*/
}
break;
default:
}
}
/*NOTREACHED*/
return (NULL);
}
static const char *
pu_getpname(const char *arg0)
{
char *p;
/*
* Guard against '/' at end of command invocation.
*/
for (;;) {
if (p == NULL) {
break;
} else {
if (*(p + 1) == '\0') {
*p = '\0';
continue;
}
pname = p + 1;
break;
}
}
return (pname);
}
int
{
char c;
int nopts = 0;
const char *classpath;
const char *libpath;
const char *err_desc;
int explain_ex = 1;
FILE *p;
(void) chdir("/");
#if !defined(TEXT_DOMAIN) /* Should be defined with cc -D. */
#endif
(void) textdomain(TEXT_DOMAIN);
opterr = 0;
switch (c) {
case 'l': /* -l option */
lflag++;
sizeof (log_severity));
break;
default:
usage();
/*NOTREACHED*/
}
}
/*
* Check permission
*/
if (!priv_ineffect(PRIV_SYS_RES_CONFIG))
/*
* In order to avoid problems with arbitrary thread selection
* when handling asynchronous signals, dedicate a thread to
* look after these signals.
*/
if (sigemptyset(&hdl_set) < 0 ||
/*
* If the -l flag is supplied, terminate the SMF service and
* run interactively from the command line.
*/
if (lflag) {
/*
* Since disabling a service isn't synchronous, use the
* synchronous option from svcadm to achieve synchronous
* behaviour.
* This is not very satisfactory, but since this is only
* for use in debugging scenarios, it will do until there
* is a C API to synchronously shutdown a service in SMF.
*/
pu_die("could not temporarily disable service: %s\n",
} else {
/*
* Check if we are running as a SMF service. If we
* aren't, terminate this process after enabling the
* service.
*/
pu_die("could not enable "
"service: %s\n", SMF_SVC_INSTANCE);
return (E_PO_SUCCESS);
}
}
/*
* Establish the classpath and LD_LIBRARY_PATH for native
* methods, and get the interpreter going.
*/
} else {
/*
* Check the components to make sure they're absolute
* paths.
*/
if (*cur != '/')
"POOLD_CLASSPATH must contain absolute "
"components\n"));
}
}
len);
/*
* Use jvm_tmp when creating the jvm to prevent race
* conditions with signal handlers. As soon as the call
* returns, assign the global jvm to jvm_tmp.
*/
/*
* Locate the Poold class and construct an instance. A side
* effect of this is that the poold instance's logHelper will be
* initialized, establishing loggers for logging errors from
* this point on. (Note, in the event of an unanticipated
* exception, poold will invoke die() itself.)
*/
goto destroy;
goto destroy;
"()V")) == NULL)
goto destroy;
== NULL)
goto destroy;
goto destroy;
/*
* -l <level> was specified, indicating that messages are to be
* logged to the console only.
*/
if (strlen(log_severity) > 0) {
log_severity)) == NULL)
goto destroy;
NULL) {
explain_ex = 0;
goto destroy;
}
} else
goto destroy;
/*
* Grab a global reference to poold for use in our signal
* handlers.
*/
/*
* Ready LD_JAVA logging.
*/
goto destroy;
goto destroy;
goto destroy;
goto destroy;
goto destroy;
goto destroy;
goto destroy;
base_log_fid)))
goto destroy;
goto destroy;
goto destroy;
/*
* If invoked directly and -l is specified, forking is not
* desired.
*/
if (!lflag)
switch (forkall()) {
case 0:
(void) setsid();
break;
case -1:
/*NOTREACHED*/
default:
return (E_PO_SUCCESS);
}
(void) pthread_mutex_lock(&instance_running_lock);
instance_running = 1;
(void) pthread_mutex_unlock(&instance_running_lock);
goto destroy;
return (E_PO_SUCCESS);
}