📄 jk_jni_worker.c
字号:
/*
* Copyright 1999-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***************************************************************************
* Description: In process JNI worker *
* Author: Gal Shachor <shachor@il.ibm.com> *
* Based on: *
* Version: $Revision: 300224 $ *
***************************************************************************/
#if !defined(WIN32) && !defined(NETWARE) && !defined(AS400)
#include <dlfcn.h>
#endif
#include <jni.h>
#include "jk_pool.h"
#include "jk_jni_worker.h"
#include "jk_util.h"
#if defined LINUX && defined APACHE2_SIGHACK
#include <pthread.h>
#include <signal.h>
#include <bits/signum.h>
#endif
#ifdef NETWARE
#ifdef __NOVELL_LIBC__
#include <dlfcn.h>
#else
#include <nwthread.h>
#include <nwadv.h>
#endif
#endif
#ifndef JNI_VERSION_1_1
#define JNI_VERSION_1_1 0x00010001
#endif
/* probably on an older system that doesn't support RTLD_NOW or RTLD_LAZY.
* The below define is a lie since we are really doing RTLD_LAZY since the
* system doesn't support RTLD_NOW.
*/
#ifndef RTLD_NOW
#define RTLD_NOW 1
#endif
#ifndef RTLD_GLOBAL
#define RTLD_GLOBAL 0
#endif
#define null_check(e) if ((e) == 0) return JK_FALSE
jint(JNICALL * jni_get_default_java_vm_init_args) (void *) = NULL;
jint(JNICALL * jni_create_java_vm) (JavaVM **, JNIEnv **, void *) = NULL;
#ifdef AS400
jint(JNICALL * jni_get_created_java_vms) (JavaVM **, long, long *) = NULL;
#else
jint(JNICALL * jni_get_created_java_vms) (JavaVM **, int, int *) = NULL;
#endif
#define TC33_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/modules/server/JNIEndpoint")
#define TC32_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/service/JNIEndpoint")
static jk_worker_t *the_singleton_jni_worker = NULL;
struct jni_worker
{
int was_verified;
int was_initialized;
jk_pool_t p;
jk_pool_atom_t buf[TINY_POOL_SIZE];
/*
* JVM Object pointer.
*/
JavaVM *jvm;
/*
* [V] JNIEnv used for boostraping from validate -> init w/o an attach
*/
JNIEnv *tmp_env;
/*
* Web Server to Java bridge, instance and class.
*/
jobject jk_java_bridge_object;
jclass jk_java_bridge_class;
/*
* Java methods ids, to jump into the JVM
*/
jmethodID jk_startup_method;
jmethodID jk_service_method;
jmethodID jk_shutdown_method;
/*
* Command line for tomcat startup
*/
char *tomcat_cmd_line;
/*
* Bridge Type, Tomcat 32/33/40/41/5
*/
unsigned bridge_type;
/*
* Classpath
*/
char *tomcat_classpath;
/*
* Full path to the jni javai/jvm dll
*/
char *jvm_dll_path;
/*
* Initial Java heap size
*/
unsigned tomcat_ms;
/*
* Max Java heap size
*/
unsigned tomcat_mx;
/*
* Java system properties
*/
char **sysprops;
#ifdef JNI_VERSION_1_2
/*
* Java 2 initialization options (-X... , -verbose etc.)
*/
char **java2opts;
/*
* Java 2 lax/strict option checking (bool)
*/
int java2lax;
#endif
/*
* stdout and stderr file names for Java
*/
char *stdout_name;
char *stderr_name;
char *name;
jk_worker_t worker;
};
typedef struct jni_worker jni_worker_t;
struct jni_endpoint
{
int attached;
JNIEnv *env;
jni_worker_t *worker;
jk_endpoint_t endpoint;
};
typedef struct jni_endpoint jni_endpoint_t;
static int load_jvm_dll(jni_worker_t * p, jk_logger_t *l);
static int open_jvm(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l);
static int open_jvm1(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l);
#ifdef JNI_VERSION_1_2
static int detect_jvm_version(jk_logger_t *l);
static int open_jvm2(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l);
#endif
static int get_bridge_object(jni_worker_t * p, JNIEnv * env, jk_logger_t *l);
static int get_method_ids(jni_worker_t * p, JNIEnv * env, jk_logger_t *l);
static JNIEnv *attach_to_jvm(jni_worker_t * p, jk_logger_t *l);
static void detach_from_jvm(jni_worker_t * p, jk_logger_t *l);
/*
Duplicate string and convert it to ASCII on EBDIC based systems
Needed for at least AS/400 and BS2000 but what about other EBDIC systems ?
*/
static void *strdup_ascii(jk_pool_t *p, char *s)
{
char *rc;
rc = jk_pool_strdup(p, s);
#if defined(AS400) || defined(_OSD_POSIX)
jk_xlate_to_ascii(rc, strlen(rc));
#endif
return rc;
}
#if defined LINUX && defined APACHE2_SIGHACK
static void linux_signal_hack()
{
sigset_t newM;
sigset_t old;
sigemptyset(&newM);
pthread_sigmask(SIG_SETMASK, &newM, &old);
sigdelset(&old, SIGUSR1);
sigdelset(&old, SIGUSR2);
sigdelset(&old, SIGUNUSED);
sigdelset(&old, SIGRTMIN);
sigdelset(&old, SIGRTMIN + 1);
sigdelset(&old, SIGRTMIN + 2);
pthread_sigmask(SIG_SETMASK, &old, NULL);
}
static void print_signals(sigset_t * sset)
{
int sig;
for (sig = 1; sig < 20; sig++) {
if (sigismember(sset, sig)) {
printf(" %d", sig);
}
}
printf("\n");
}
#endif
static int JK_METHOD service(jk_endpoint_t *e,
jk_ws_service_t *s,
jk_logger_t *l, int *is_recoverable_error)
{
jni_endpoint_t *p;
jint rc;
JK_TRACE_ENTER(l);
if (!e || !e->endpoint_private || !s) {
JK_LOG_NULL_PARAMS(l);
JK_TRACE_EXIT(l);
return JK_FALSE;
}
p = e->endpoint_private;
if (!is_recoverable_error) {
JK_TRACE_EXIT(l);
return JK_FALSE;
}
if (!p->attached) {
/* Try to attach */
if (!(p->env = attach_to_jvm(p->worker, l))) {
jk_log(l, JK_LOG_EMERG, "Attach failed");
/* Is it recoverable ?? */
*is_recoverable_error = JK_TRUE;
JK_TRACE_EXIT(l);
return JK_FALSE;
}
p->attached = JK_TRUE;
}
/* we are attached now */
/*
* When we call the JVM we cannot know what happens
* So we can not recover !!!
*/
*is_recoverable_error = JK_FALSE;
jk_log(l, JK_LOG_DEBUG, "In service, calling Tomcat...");
rc = (*(p->env))->CallIntMethod(p->env,
p->worker->jk_java_bridge_object,
p->worker->jk_service_method,
/* [V] For some reason gcc likes this pointer -> int -> jlong conversion, */
/* but not the direct pointer -> jlong conversion. I hope it's okay. */
#ifdef AS400
s, l
#else
(jlong) (int)s, (jlong) (int)l
#endif
);
/* [V] Righ now JNIEndpoint::service() only returns 1 or 0 */
if (rc) {
jk_log(l, JK_LOG_DEBUG, "Tomcat returned OK, done");
JK_TRACE_EXIT(l);
return JK_TRUE;
}
else {
jk_log(l, JK_LOG_ERROR, "Tomcat FAILED!");
JK_TRACE_EXIT(l);
return JK_FALSE;
}
}
static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l)
{
jni_endpoint_t *p;
JK_TRACE_ENTER(l);
if (!e || !*e || !(*e)->endpoint_private) {
JK_LOG_NULL_PARAMS(l);
JK_TRACE_EXIT(l);
return JK_FALSE;
}
p = (*e)->endpoint_private;
if (p->attached) {
detach_from_jvm(p->worker, l);
}
free(p);
*e = NULL;
JK_TRACE_EXIT(l);
return JK_TRUE;
}
static int JK_METHOD validate(jk_worker_t *pThis,
jk_map_t *props,
jk_worker_env_t *we, jk_logger_t *l)
{
jni_worker_t *p;
int mem_config = 0;
int btype = 0;
const char *str_config = NULL;
JNIEnv *env;
JK_TRACE_ENTER(l);
if (!pThis || !pThis->worker_private) {
JK_LOG_NULL_PARAMS(l);
JK_TRACE_EXIT(l);
return JK_FALSE;
}
p = pThis->worker_private;
if (p->was_verified) {
jk_log(l, JK_LOG_DEBUG, "been here before, done");
JK_TRACE_EXIT(l);
return JK_TRUE;
}
if (jk_get_worker_mx(props, p->name, (unsigned int *)&mem_config)) {
p->tomcat_mx = mem_config;
}
if (jk_get_worker_ms(props, p->name, (unsigned int *)&mem_config)) {
p->tomcat_ms = mem_config;
}
if (jk_get_worker_classpath(props, p->name, &str_config)) {
p->tomcat_classpath = jk_pool_strdup(&p->p, str_config);
}
if (!p->tomcat_classpath) {
jk_log(l, JK_LOG_EMERG, "no classpath");
JK_TRACE_EXIT(l);
return JK_FALSE;
}
if (jk_get_worker_bridge_type(props, p->name, (unsigned int *)&btype)) {
p->bridge_type = btype;
}
if (jk_get_worker_jvm_path(props, p->name, &str_config)) {
p->jvm_dll_path = jk_pool_strdup(&p->p, str_config);
}
if (!p->jvm_dll_path || !jk_file_exists(p->jvm_dll_path)) {
jk_log(l, JK_LOG_EMERG, "no jvm_dll_path");
JK_TRACE_EXIT(l);
return JK_FALSE;
}
if (jk_get_worker_cmd_line(props, p->name, &str_config)) {
p->tomcat_cmd_line = jk_pool_strdup(&p->p, str_config);
}
if (jk_get_worker_stdout(props, p->name, &str_config)) {
p->stdout_name = jk_pool_strdup(&p->p, str_config);
}
if (jk_get_worker_stderr(props, p->name, &str_config)) {
p->stderr_name = jk_pool_strdup(&p->p, str_config);
}
if (jk_get_worker_sysprops(props, p->name, &str_config)) {
p->sysprops = jk_parse_sysprops(&p->p, str_config);
}
#ifdef JNI_VERSION_1_2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -