poold.c revision 414388d7cb2ee98771e2ac7c2338c460abd44304
/*
* 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"
#if defined(sparc)
#define PLAT "sparc"
#else
#if defined(i386)
#define PLAT "i386"
#else
#endif
#endif
#define PID_PROPERTY_NAME "system.poold.pid"
#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
{
}
/*
* Update the "system.poold.pid" to reflect this instance of poold only
* if the property hasn't been set already to reflect an existing
* process, and mode is not set to PGAS_GET_ONLY. Returns the
* property's pre-existing value, or -1 otherwise.
*/
static pid_t
{
if (!(conf = pool_conf_alloc()))
return ((pid_t)-1);
(void) pool_conf_free(conf);
return ((pid_t)-1);
}
if (!(val = pool_value_alloc())) {
(void) pool_conf_close(conf);
return ((pid_t)-1);
}
(void) pool_value_free(val);
(void) pool_conf_close(conf);
return ((pid_t)-1);
}
} else {
}
if (mode == PGAS_GET_AND_SET) {
(void) pool_conf_commit(conf, 0);
}
(void) pool_value_free(val);
(void) pool_conf_close(conf);
}
/*
* 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;
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;
(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*/
}
}
/*
* Verify no other poold is running. This condition is checked
* again later, but should be checked now since it is more
* serious (i.e. should be reported before) than a lack of
* privileges.
*/
/*
* Check permission
*/
if (!priv_ineffect(PRIV_SYS_RES_CONFIG))
/*
* 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);
/*
* XXX - Forking after the VM is created is desirable to
* guarantee reporting of errors, but cannot be done (see
* 4919246).
*
* If invoked by libpool(3LIB), it's set the system.poold.pid
* property and forked already. If invoked directly and -l is
* specified, forking is not desired.
*/
switch (fork()) {
case 0:
(void) setsid();
break;
case -1:
/*NOTREACHED*/
default:
return (E_PO_SUCCESS);
}
/*
* 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 ||
/*
* 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;
/*
* Now we're ready to start poold. Store our pid in the pools
* configuration to mark that an instance of poold is active,
* then invoke Poold.run(), which does not normally return.
*
* Note that the ignoreUpdates variable in Poold is used to
* allow Poold to ignore the pools configuration update that
* this change triggers. If this code is ever modified to
* remove or modify this logic, then the Poold class must also
* be modified to keep the actions synchronized.
*/
(void) pthread_mutex_lock(&instance_running_lock);
instance_running = 1;
(void) pthread_mutex_unlock(&instance_running_lock);
goto destroy;
return (E_PO_SUCCESS);
}