Merge
This commit is contained in:
commit
7aa3cba238
@ -263,239 +263,13 @@ $(eval $(call SetupBuildDemo, TransparentRuler, \
|
||||
MAIN_CLASS := transparentruler.Ruler, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupBuildDemo, jconsole-plugin, \
|
||||
DEMO_SUBDIR := scripting, \
|
||||
SRC_SUB_DIR := src, \
|
||||
MAIN_CLASS := NONE, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupBuildDemo, FullThreadDump, \
|
||||
DEMO_SUBDIR := management, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupBuildDemo, JTop, \
|
||||
DEMO_SUBDIR := management, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupBuildDemo, MemoryMonitor, \
|
||||
DEMO_SUBDIR := management, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupBuildDemo, VerboseGC, \
|
||||
DEMO_SUBDIR := management, \
|
||||
))
|
||||
|
||||
################################################################################
|
||||
# Build JVMTI demos.
|
||||
|
||||
# Setup make rules for building a JVMTI demo.
|
||||
#
|
||||
# Parameter 1 is the name of the rule. This name is used as variable prefix,
|
||||
# and the targets generated are listed in a variable by that name.
|
||||
#
|
||||
# Remaining parameters are named arguments. These include:
|
||||
# EXTRA_SRC_SUBDIR Also include these subdirectories
|
||||
# TOOLCHAIN Optionally specify toolchain to use
|
||||
SetupBuildJvmtiDemo = $(NamedParamsMacroTemplate)
|
||||
define SetupBuildJvmtiDemoBody
|
||||
$1_SRC := \
|
||||
$(DEMO_SHARE_SRC)/jvmti/$1 \
|
||||
$$(wildcard $$(addprefix $(DEMO_SHARE_SRC)/jvmti/, \
|
||||
agent_util $$($1_EXTRA_SRC_SUBDIR)))
|
||||
|
||||
### Build the native lib
|
||||
$1_CFLAGS_INCLUDE := $$(addprefix -I, $$($1_SRC))
|
||||
|
||||
$1_CXXFLAGS := $$($1_CFLAGS_INCLUDE) $(CXXFLAGS_JDKLIB) $(CXXFLAGS_DEBUG_SYMBOLS)
|
||||
|
||||
ifeq ($$($1_TOOLCHAIN), TOOLCHAIN_LINK_CXX)
|
||||
# For C++, we also need some special treatment.
|
||||
$1_LDFLAGS := $$(LDFLAGS_CXX_JDK)
|
||||
$1_LIBS := $(LIBCXX)
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_CPU_ARCH), sparc)
|
||||
$1_CXXFLAGS := $$(filter-out -xregs=no%appl, $$($1_CXXFLAGS))
|
||||
endif
|
||||
endif
|
||||
|
||||
# Remove the -incremental:no setting to get .ilk-files like in the old build.
|
||||
$$(eval $$(call SetupNativeCompilation, BUILD_DEMO_JVMTI_NATIVE_$1, \
|
||||
SRC := $$($1_SRC), \
|
||||
TOOLCHAIN := $$($1_TOOLCHAIN), \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $$($1_CFLAGS_INCLUDE) $$(CFLAGS_JDKLIB) $$(CFLAGS_DEBUG_SYMBOLS), \
|
||||
CXXFLAGS := $$($1_CXXFLAGS), \
|
||||
LDFLAGS := $(filter-out -incremental:no -opt:ref, $$(LDFLAGS_JDKLIB)) \
|
||||
$$($1_LDFLAGS), \
|
||||
LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN), \
|
||||
LIBS := $$($1_LIBS), \
|
||||
LIBS_solaris := -lc, \
|
||||
VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
|
||||
RC_FLAGS := $$(RC_FLAGS) \
|
||||
-D "JDK_FNAME=$1.dll" \
|
||||
-D "JDK_INTERNAL_NAME=$1" \
|
||||
-D "JDK_FTYPE=0x2L", \
|
||||
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/demos/native/jvmti/$1, \
|
||||
OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/demos/image/jvmti/$1/lib, \
|
||||
LIBRARY := $1, \
|
||||
STRIP_SYMBOLS := false, \
|
||||
))
|
||||
|
||||
$1 += $$(BUILD_DEMO_JVMTI_NATIVE_$1)
|
||||
|
||||
### Build the jar, if we have java sources
|
||||
ifneq ($$(wildcard $(DEMO_SHARE_SRC)/jvmti/$1/*.java), )
|
||||
$$(eval $$(call SetupJavaCompilation, BUILD_DEMO_JVMTI_JAVA_$1, \
|
||||
SETUP := GENERATE_USINGJDKBYTECODE, \
|
||||
SRC := $(DEMO_SHARE_SRC)/jvmti/$1, \
|
||||
BIN := $(SUPPORT_OUTPUTDIR)/demos/classes/jvmti/$1, \
|
||||
COPY := $(COPY_TO_JAR), \
|
||||
JAR := $(SUPPORT_OUTPUTDIR)/demos/image/jvmti/$1/$1.jar, \
|
||||
EXTRA_MANIFEST_ATTR := Main-Class: \n, \
|
||||
MANIFEST := $(DEMO_MANIFEST), \
|
||||
))
|
||||
|
||||
$1 += $$(BUILD_DEMO_JVMTI_JAVA_$1_JAR)
|
||||
endif
|
||||
|
||||
### Build the source zip
|
||||
$1_EXCLUDE_FILES := \
|
||||
$$(wildcard $$(patsubst %, $(DEMO_SHARE_SRC)/jvmti/%/README.txt, \
|
||||
agent_util $$($1_EXTRA_SRC_SUBDIR))) \
|
||||
$$(wildcard $$(patsubst %, $(DEMO_SHARE_SRC)/jvmti/%/sample.makefile.txt, \
|
||||
agent_util $$($1_EXTRA_SRC_SUBDIR)))
|
||||
|
||||
$$(eval $$(call SetupZipArchive, BUILD_DEMO_JVMTI_SRC_$1, \
|
||||
SRC := $$($1_SRC), \
|
||||
EXCLUDE_FILES := $$($1_EXCLUDE_FILES), \
|
||||
ZIP := $(SUPPORT_OUTPUTDIR)/demos/image/jvmti/$1/src.zip, \
|
||||
))
|
||||
|
||||
$1 += $$(BUILD_DEMO_JVMTI_SRC_$1)
|
||||
|
||||
# Copy files to image
|
||||
$(SUPPORT_OUTPUTDIR)/demos/image/jvmti/$1/README.txt: $(DEMO_SHARE_SRC)/jvmti/$1/README.txt
|
||||
$$(call install-file)
|
||||
$(CHMOD) -f ug+w $$@
|
||||
|
||||
$1 += $(SUPPORT_OUTPUTDIR)/demos/image/jvmti/$1/README.txt
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
# These lib and exp files normally end up in OBJECT_DIR but for demos they
|
||||
# are supposed to be included in the distro. Since they are created as
|
||||
# a side-effect of the library compilation, make does not know about them.
|
||||
$1_SUPPORT_OUTPUTDIR := $(SUPPORT_OUTPUTDIR)/demos/native/jvmti/$1
|
||||
$1_IMAGE_OUTPUTDIR := $(SUPPORT_OUTPUTDIR)/demos/image/jvmti/$1/lib
|
||||
|
||||
$$($1_SUPPORT_OUTPUTDIR)/$1.lib: $$(BUILD_DEMO_JVMTI_NATIVE_$1)
|
||||
|
||||
$$($1_SUPPORT_OUTPUTDIR)/$1.exp: $$(BUILD_DEMO_JVMTI_NATIVE_$1)
|
||||
|
||||
$$($1_IMAGE_OUTPUTDIR)/$1.lib: $$($1_SUPPORT_OUTPUTDIR)/$1.lib
|
||||
$$(call install-file)
|
||||
|
||||
$$($1_IMAGE_OUTPUTDIR)/$1.exp: $$($1_SUPPORT_OUTPUTDIR)/$1.exp
|
||||
$$(call install-file)
|
||||
|
||||
$1 += $$($1_IMAGE_OUTPUTDIR)/$1.lib $$($1_IMAGE_OUTPUTDIR)/$1.exp
|
||||
endif
|
||||
|
||||
TARGETS += $$($1)
|
||||
endef
|
||||
|
||||
$(eval $(call SetupBuildJvmtiDemo, compiledMethodLoad))
|
||||
$(eval $(call SetupBuildJvmtiDemo, gctest))
|
||||
$(eval $(call SetupBuildJvmtiDemo, heapViewer))
|
||||
$(eval $(call SetupBuildJvmtiDemo, versionCheck))
|
||||
|
||||
$(eval $(call SetupBuildJvmtiDemo, heapTracker, \
|
||||
EXTRA_SRC_SUBDIR := java_crw_demo, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupBuildJvmtiDemo, minst, \
|
||||
EXTRA_SRC_SUBDIR := java_crw_demo, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupBuildJvmtiDemo, mtrace, \
|
||||
EXTRA_SRC_SUBDIR := java_crw_demo, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupBuildJvmtiDemo, waiters, \
|
||||
TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
|
||||
))
|
||||
|
||||
################################################################################
|
||||
# Build the Poller demo (on Solaris only).
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), solaris)
|
||||
DEMO_SOLARIS_SRC := $(JDK_TOPDIR)/src/demo/solaris
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_DEMO_JAVA_Poller, \
|
||||
SETUP := GENERATE_USINGJDKBYTECODE, \
|
||||
SRC := $(DEMO_SOLARIS_SRC)/jni/Poller, \
|
||||
BIN := $(SUPPORT_OUTPUTDIR)/demos/classes/jni/Poller, \
|
||||
HEADERS := $(SUPPORT_OUTPUTDIR)/demos/classes/jni/Poller, \
|
||||
JAR := $(SUPPORT_OUTPUTDIR)/demos/image/jni/Poller/Poller.jar, \
|
||||
MANIFEST := $(SUPPORT_OUTPUTDIR)/demos/java-main-manifest.mf, \
|
||||
SRCZIP := $(SUPPORT_OUTPUTDIR)/demos/image/jni/Poller/src.zip, \
|
||||
COPY := README.txt Poller.c, \
|
||||
JARMAIN := Client, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_DEMO_JAVA_Poller)
|
||||
|
||||
$(eval $(call SetupNativeCompilation, BUILD_DEMO_NATIVE_Poller, \
|
||||
SRC := $(DEMO_SOLARIS_SRC)/jni/Poller, \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
-I$(SUPPORT_OUTPUTDIR)/demos/classes/jni/Poller, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB), \
|
||||
LIBS_solaris := -lc, \
|
||||
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/demos/native/jni/Poller, \
|
||||
OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/demos/native, \
|
||||
LIBRARY := Poller, \
|
||||
STRIP_SYMBOLS := false, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_DEMO_NATIVE_Poller)
|
||||
|
||||
# We can only compile native code after java has been compiled (since we
|
||||
# depend on generated .h files)
|
||||
$(SUPPORT_OUTPUTDIR)/demos/native/jni/Poller/Poller.o: \
|
||||
$(BUILD_DEMO_JAVA_Poller)
|
||||
|
||||
# Copy to image
|
||||
$(SUPPORT_OUTPUTDIR)/demos/image/jni/Poller/README.txt: \
|
||||
$(DEMO_SOLARIS_SRC)/jni/Poller/README.txt
|
||||
$(call install-file)
|
||||
$(CHMOD) -f ug+w $@
|
||||
|
||||
TARGETS += $(SUPPORT_OUTPUTDIR)/demos/image/jni/Poller/README.txt
|
||||
|
||||
$(SUPPORT_OUTPUTDIR)/demos/image/jni/Poller/lib/libPoller.so: \
|
||||
$(SUPPORT_OUTPUTDIR)/demos/native/libPoller.so
|
||||
$(call install-file)
|
||||
|
||||
TARGETS += $(SUPPORT_OUTPUTDIR)/demos/image/jni/Poller/lib/libPoller.so
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Copy html and README files.
|
||||
|
||||
$(SUPPORT_OUTPUTDIR)/demos/image/management/index.html: $(DEMO_SHARE_SRC)/management/index.html
|
||||
$(call install-file)
|
||||
$(CHMOD) -f ug+w $@
|
||||
|
||||
$(SUPPORT_OUTPUTDIR)/demos/image/jvmti/index.html: $(DEMO_SHARE_SRC)/jvmti/index.html
|
||||
$(call install-file)
|
||||
$(CHMOD) -f ug+w $@
|
||||
|
||||
$(SUPPORT_OUTPUTDIR)/demos/image/README: $(DEMO_SHARE_SRC)/README
|
||||
$(call install-file)
|
||||
|
||||
TARGETS += $(SUPPORT_OUTPUTDIR)/demos/image/management/index.html \
|
||||
$(SUPPORT_OUTPUTDIR)/demos/image/jvmti/index.html \
|
||||
$(SUPPORT_OUTPUTDIR)/demos/image/README
|
||||
TARGETS += $(SUPPORT_OUTPUTDIR)/demos/image/README
|
||||
|
||||
################################################################################
|
||||
# Copy netbeans project files.
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,11 +30,19 @@ include MakeBase.gmk
|
||||
include JavaCompilation.gmk
|
||||
include SetupJavaCompilers.gmk
|
||||
|
||||
$(eval $(call IncludeCustomExtension, jdk, CompileTools.gmk))
|
||||
|
||||
################################################################################
|
||||
|
||||
# Use += to be able to add to this from a custom extension
|
||||
BUILD_TOOLS_SRC_DIRS += \
|
||||
$(JDK_TOPDIR)/make/src/classes \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes \
|
||||
#
|
||||
|
||||
$(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := $(JDK_TOPDIR)/make/src/classes $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes, \
|
||||
SRC := $(BUILD_TOOLS_SRC_DIRS), \
|
||||
EXCLUDES := build/tools/deps \
|
||||
build/tools/jigsaw, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes))
|
||||
|
@ -1,65 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
default: all
|
||||
|
||||
include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
|
||||
################################################################################
|
||||
|
||||
SAMPLE_TARGET_DIR := $(SUPPORT_OUTPUTDIR)/sample/image
|
||||
SAMPLE_SOURCE_DIR := $(JDK_TOPDIR)/src/sample/share
|
||||
SAMPLE_SOLARIS_SOURCE_DIR := $(JDK_TOPDIR)/src/sample/solaris
|
||||
|
||||
# Exclude the vm directory
|
||||
$(eval $(call SetupCopyFiles, COPY_SHARE_SAMPLES, \
|
||||
SRC := $(SAMPLE_SOURCE_DIR), \
|
||||
DEST := $(SAMPLE_TARGET_DIR), \
|
||||
FILES := $(filter-out $(SAMPLE_SOURCE_DIR)/vm/%, \
|
||||
$(call CacheFind, $(SAMPLE_SOURCE_DIR))), \
|
||||
))
|
||||
|
||||
TARGETS += $(COPY_SHARE_SAMPLES)
|
||||
|
||||
ifneq (, $(filter $(OPENJDK_TARGET_OS), solaris macosx))
|
||||
$(eval $(call SetupCopyFiles, COPY_SOLARIS_SAMPLES, \
|
||||
SRC := $(SAMPLE_SOLARIS_SOURCE_DIR), \
|
||||
DEST := $(SAMPLE_TARGET_DIR), \
|
||||
FILES := $(call CacheFind, $(SAMPLE_SOLARIS_SOURCE_DIR)), \
|
||||
))
|
||||
|
||||
TARGETS += $(COPY_SOLARIS_SAMPLES)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
||||
$(eval $(call IncludeCustomExtension, jdk, CopySamples.gmk))
|
||||
|
||||
################################################################################
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
.PHONY: all default
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,6 +28,9 @@ _TOOLS_GMK := 1
|
||||
|
||||
include JavaCompilation.gmk
|
||||
|
||||
# Hook to include the corresponding custom file, if present.
|
||||
$(eval $(call IncludeCustomExtension, jdk, Tools.gmk))
|
||||
|
||||
################################################################################
|
||||
# To avoid reevaluating the compilation setup for the tools each time this file
|
||||
# is included, the actual compilation is handled by CompileTools.gmk. The
|
||||
|
@ -24,3 +24,5 @@ JIS_X_0208
|
||||
JIS_X_0212
|
||||
JIS_X_0208_Solaris
|
||||
JIS_X_0212_Solaris
|
||||
MS932
|
||||
SJIS # SJIS must go together with MS932 to support sun.nio.cs.map
|
||||
|
@ -1,4 +1,4 @@
|
||||
The source code provided with samples and demos for the JDK is meant
|
||||
The source code provided with demos for the JDK is meant
|
||||
to illustrate the usage of a given feature or technique and has been
|
||||
deliberately simplified. Additional steps required for a
|
||||
production-quality application, such as security checks, input
|
||||
|
@ -1,35 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
agent_util sources
|
||||
|
||||
Just some shared generic source used by several of the demos.
|
||||
|
@ -1,309 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#include <agent_util.h>
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* Generic C utility functions */
|
||||
|
||||
/* Send message to stdout or whatever the data output location is */
|
||||
void
|
||||
stdout_message(const char * format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
(void)vfprintf(stdout, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Send message to stderr or whatever the error output location is and exit */
|
||||
void
|
||||
fatal_error(const char * format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
(void)vfprintf(stderr, format, ap);
|
||||
(void)fflush(stderr);
|
||||
va_end(ap);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
/* Get a token from a string (strtok is not MT-safe)
|
||||
* str String to scan
|
||||
* seps Separation characters
|
||||
* buf Place to put results
|
||||
* max Size of buf
|
||||
* Returns NULL if no token available or can't do the scan.
|
||||
*/
|
||||
char *
|
||||
get_token(char *str, char *seps, char *buf, int max)
|
||||
{
|
||||
int len;
|
||||
|
||||
buf[0] = 0;
|
||||
if ( str==NULL || str[0]==0 ) {
|
||||
return NULL;
|
||||
}
|
||||
str += strspn(str, seps);
|
||||
if ( str[0]==0 ) {
|
||||
return NULL;
|
||||
}
|
||||
len = (int)strcspn(str, seps);
|
||||
if ( len >= max ) {
|
||||
return NULL;
|
||||
}
|
||||
(void)strncpy(buf, str, len);
|
||||
buf[len] = 0;
|
||||
return str+len;
|
||||
}
|
||||
|
||||
/* Determines if a class/method is specified by a list item
|
||||
* item String that represents a pattern to match
|
||||
* If it starts with a '*', then any class is allowed
|
||||
* If it ends with a '*', then any method is allowed
|
||||
* cname Class name, e.g. "java.lang.Object"
|
||||
* mname Method name, e.g. "<init>"
|
||||
* Returns 1(true) or 0(false).
|
||||
*/
|
||||
static int
|
||||
covered_by_list_item(char *item, char *cname, char *mname)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = (int)strlen(item);
|
||||
if ( item[0]=='*' ) {
|
||||
if ( strncmp(mname, item+1, len-1)==0 ) {
|
||||
return 1;
|
||||
}
|
||||
} else if ( item[len-1]=='*' ) {
|
||||
if ( strncmp(cname, item, len-1)==0 ) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
int cname_len;
|
||||
|
||||
cname_len = (int)strlen(cname);
|
||||
if ( strncmp(cname, item, (len>cname_len?cname_len:len))==0 ) {
|
||||
if ( cname_len >= len ) {
|
||||
/* No method name supplied in item, we must have matched */
|
||||
return 1;
|
||||
} else {
|
||||
int mname_len;
|
||||
|
||||
mname_len = (int)strlen(mname);
|
||||
item += cname_len+1;
|
||||
len -= cname_len+1;
|
||||
if ( strncmp(mname, item, (len>mname_len?mname_len:len))==0 ) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determines if a class/method is specified by this list
|
||||
* list String of comma separated pattern items
|
||||
* cname Class name, e.g. "java.lang.Object"
|
||||
* mname Method name, e.g. "<init>"
|
||||
* Returns 1(true) or 0(false).
|
||||
*/
|
||||
static int
|
||||
covered_by_list(char *list, char *cname, char *mname)
|
||||
{
|
||||
char token[1024];
|
||||
char *next;
|
||||
|
||||
if ( list[0] == 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
next = get_token(list, ",", token, sizeof(token));
|
||||
while ( next != NULL ) {
|
||||
if ( covered_by_list_item(token, cname, mname) ) {
|
||||
return 1;
|
||||
}
|
||||
next = get_token(next, ",", token, sizeof(token));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determines which class and methods we are interested in
|
||||
* cname Class name, e.g. "java.lang.Object"
|
||||
* mname Method name, e.g. "<init>"
|
||||
* include_list Empty or an explicit list for inclusion
|
||||
* exclude_list Empty or an explicit list for exclusion
|
||||
* Returns 1(true) or 0(false).
|
||||
*/
|
||||
int
|
||||
interested(char *cname, char *mname, char *include_list, char *exclude_list)
|
||||
{
|
||||
if ( exclude_list!=NULL && exclude_list[0]!=0 &&
|
||||
covered_by_list(exclude_list, cname, mname) ) {
|
||||
return 0;
|
||||
}
|
||||
if ( include_list!=NULL && include_list[0]!=0 &&
|
||||
!covered_by_list(include_list, cname, mname) ) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* Generic JVMTI utility functions */
|
||||
|
||||
/* Every JVMTI interface returns an error code, which should be checked
|
||||
* to avoid any cascading errors down the line.
|
||||
* The interface GetErrorName() returns the actual enumeration constant
|
||||
* name, making the error messages much easier to understand.
|
||||
*/
|
||||
void
|
||||
check_jvmti_error(jvmtiEnv *jvmti, jvmtiError errnum, const char *str)
|
||||
{
|
||||
if ( errnum != JVMTI_ERROR_NONE ) {
|
||||
char *errnum_str;
|
||||
|
||||
errnum_str = NULL;
|
||||
(void)(*jvmti)->GetErrorName(jvmti, errnum, &errnum_str);
|
||||
|
||||
fatal_error("ERROR: JVMTI: %d(%s): %s\n", errnum,
|
||||
(errnum_str==NULL?"Unknown":errnum_str),
|
||||
(str==NULL?"":str));
|
||||
}
|
||||
}
|
||||
|
||||
/* All memory allocated by JVMTI must be freed by the JVMTI Deallocate
|
||||
* interface.
|
||||
*/
|
||||
void
|
||||
deallocate(jvmtiEnv *jvmti, void *ptr)
|
||||
{
|
||||
jvmtiError error;
|
||||
|
||||
error = (*jvmti)->Deallocate(jvmti, ptr);
|
||||
check_jvmti_error(jvmti, error, "Cannot deallocate memory");
|
||||
}
|
||||
|
||||
/* Allocation of JVMTI managed memory */
|
||||
void *
|
||||
allocate(jvmtiEnv *jvmti, jint len)
|
||||
{
|
||||
jvmtiError error;
|
||||
void *ptr;
|
||||
|
||||
error = (*jvmti)->Allocate(jvmti, len, (unsigned char **)&ptr);
|
||||
check_jvmti_error(jvmti, error, "Cannot allocate memory");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Add demo jar file to boot class path (the BCI Tracker class must be
|
||||
* in the boot classpath)
|
||||
*
|
||||
* WARNING: This code assumes that the jar file can be found at one of:
|
||||
* ${JAVA_HOME}/demo/jvmti/${DEMO_NAME}/${DEMO_NAME}.jar
|
||||
* ${JAVA_HOME}/../demo/jvmti/${DEMO_NAME}/${DEMO_NAME}.jar
|
||||
* where JAVA_HOME may refer to the jre directory.
|
||||
* Both these values are added to the boot classpath.
|
||||
* These locations are only true for these demos, installed
|
||||
* in the JDK area. Platform specific code could be used to
|
||||
* find the location of the DLL or .so library, and construct a
|
||||
* path name to the jar file, relative to the library location.
|
||||
*/
|
||||
void
|
||||
add_demo_jar_to_bootclasspath(jvmtiEnv *jvmti, char *demo_name)
|
||||
{
|
||||
jvmtiError error;
|
||||
char *file_sep;
|
||||
int max_len;
|
||||
char *java_home;
|
||||
char jar_path[FILENAME_MAX+1];
|
||||
|
||||
java_home = NULL;
|
||||
error = (*jvmti)->GetSystemProperty(jvmti, "java.home", &java_home);
|
||||
check_jvmti_error(jvmti, error, "Cannot get java.home property value");
|
||||
if ( java_home == NULL || java_home[0] == 0 ) {
|
||||
fatal_error("ERROR: Java home not found\n");
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
file_sep = "\\";
|
||||
#else
|
||||
file_sep = "/";
|
||||
#endif
|
||||
|
||||
max_len = (int)(strlen(java_home) + strlen(demo_name)*2 +
|
||||
strlen(file_sep)*5 +
|
||||
16 /* ".." "demo" "jvmti" ".jar" NULL */ );
|
||||
if ( max_len > (int)sizeof(jar_path) ) {
|
||||
fatal_error("ERROR: Path to jar file too long\n");
|
||||
}
|
||||
(void)strcpy(jar_path, java_home);
|
||||
(void)strcat(jar_path, file_sep);
|
||||
(void)strcat(jar_path, "demo");
|
||||
(void)strcat(jar_path, file_sep);
|
||||
(void)strcat(jar_path, "jvmti");
|
||||
(void)strcat(jar_path, file_sep);
|
||||
(void)strcat(jar_path, demo_name);
|
||||
(void)strcat(jar_path, file_sep);
|
||||
(void)strcat(jar_path, demo_name);
|
||||
(void)strcat(jar_path, ".jar");
|
||||
error = (*jvmti)->AddToBootstrapClassLoaderSearch(jvmti, (const char*)jar_path);
|
||||
check_jvmti_error(jvmti, error, "Cannot add to boot classpath");
|
||||
|
||||
(void)strcpy(jar_path, java_home);
|
||||
(void)strcat(jar_path, file_sep);
|
||||
(void)strcat(jar_path, "..");
|
||||
(void)strcat(jar_path, file_sep);
|
||||
(void)strcat(jar_path, "demo");
|
||||
(void)strcat(jar_path, file_sep);
|
||||
(void)strcat(jar_path, "jvmti");
|
||||
(void)strcat(jar_path, file_sep);
|
||||
(void)strcat(jar_path, demo_name);
|
||||
(void)strcat(jar_path, file_sep);
|
||||
(void)strcat(jar_path, demo_name);
|
||||
(void)strcat(jar_path, ".jar");
|
||||
|
||||
error = (*jvmti)->AddToBootstrapClassLoaderSearch(jvmti, (const char*)jar_path);
|
||||
check_jvmti_error(jvmti, error, "Cannot add to boot classpath");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AGENT_UTIL_H
|
||||
#define AGENT_UTIL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void stdout_message(const char * format, ...);
|
||||
void fatal_error(const char * format, ...);
|
||||
char *get_token(char *str, char *seps, char *buf, int max);
|
||||
int interested(char *cname, char *mname,
|
||||
char *include_list, char *exclude_list);
|
||||
|
||||
void check_jvmti_error(jvmtiEnv *jvmti, jvmtiError errnum, const char *str);
|
||||
void deallocate(jvmtiEnv *jvmti, void *ptr);
|
||||
void *allocate(jvmtiEnv *jvmti, jint len);
|
||||
void add_demo_jar_to_bootclasspath(jvmtiEnv *jvmti, char *demo_name);
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
/* Macros for handling declaration of static/dynamic
|
||||
* Agent library Load/Attach/Unload functions
|
||||
*
|
||||
* DEF_Agent_OnLoad, DEF_Agent_OnAttach or DEF_Agent_OnUnload
|
||||
* generate the appropriate entrypoint names based on static
|
||||
* versus dynamic builds.
|
||||
*
|
||||
* STATIC_BUILD must be defined to build static versions of these libraries.
|
||||
* LIBRARY_NAME must be set to the name of the library for static builds.
|
||||
*/
|
||||
#define ADD_LIB_NAME3(name, lib) name ## lib
|
||||
#define ADD_LIB_NAME2(name, lib) ADD_LIB_NAME3(name, lib)
|
||||
#define ADD_LIB_NAME(entry) ADD_LIB_NAME2(entry, LIBRARY_NAME)
|
||||
|
||||
#define DEF_Agent_OnLoad \
|
||||
ADD_LIB_NAME(Agent_OnLoad_)(JavaVM *vm, char *options, void *reserved) \
|
||||
{ \
|
||||
jint JNICALL ADD_LIB_NAME(Agent_OnLoad_dynamic_)(JavaVM *vm, char *options, void *reserved); \
|
||||
return ADD_LIB_NAME(Agent_OnLoad_dynamic_)(vm, options, reserved); \
|
||||
} \
|
||||
jint JNICALL ADD_LIB_NAME(Agent_OnLoad_dynamic_)
|
||||
|
||||
#define DEF_Agent_OnAttach \
|
||||
ADD_LIB_NAME(Agent_OnAttach_)(JavaVM *vm, char *options, void *reserved) \
|
||||
{ \
|
||||
jint JNICALL ADD_LIB_NAME(Agent_OnAttach_dynamic_)(JavaVM *vm, char *options, void *reserved); \
|
||||
return ADD_LIB_NAME(Agent_OnAttach_dynamic_)(vm, options, reserved); \
|
||||
} \
|
||||
jint JNICALL ADD_LIB_NAME(Agent_OnAttach_dynamic_)
|
||||
|
||||
#define DEF_Agent_OnUnload \
|
||||
ADD_LIB_NAME(Agent_OnUnload_)(JavaVM *vm) \
|
||||
{ \
|
||||
void JNICALL ADD_LIB_NAME(Agent_OnUnload_dynamic_)(JavaVM *vm); \
|
||||
ADD_LIB_NAME(Agent_OnUnload_dynamic_)(vm); \
|
||||
} \
|
||||
void JNICALL ADD_LIB_NAME(Agent_OnUnload_dynamic_)
|
||||
|
||||
#else
|
||||
#define DEF_Agent_OnLoad Agent_OnLoad
|
||||
#define DEF_Agent_OnAttach Agent_OnAttach
|
||||
#define DEF_Agent_OnUnload Agent_OnUnload
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
@ -1,42 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
compiledMethodLoad
|
||||
|
||||
This agent library traces CompiledMethodLoad events along
|
||||
with the HotSpot specific compile_info parameter.
|
||||
|
||||
You can use this agent library as follows:
|
||||
|
||||
java -agentlib:compiledMethodLoad ...
|
||||
|
||||
See ${JAVA_HOME}/demo/jvmti/index.html for help running and building agents.
|
||||
|
@ -1,277 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
#include "jvmticmlr.h"
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
/* Global static data */
|
||||
static char OUTPUT_FILE[] = "compiledMethodLoad.txt";
|
||||
static FILE *fp;
|
||||
static jvmtiEnv *jvmti;
|
||||
static jrawMonitorID lock;
|
||||
|
||||
/* print a jvmtiCompiledMethodLoadDummyRecord */
|
||||
void
|
||||
print_dummy_record(jvmtiCompiledMethodLoadDummyRecord* record,
|
||||
jvmtiEnv* jvmti, FILE* fp) {
|
||||
|
||||
if (record != NULL) {
|
||||
fprintf(fp, "Dummy record detected containing message: %s\n",
|
||||
(char *)record->message);
|
||||
}
|
||||
}
|
||||
|
||||
/* print the specified stack frames */
|
||||
void
|
||||
print_stack_frames(PCStackInfo* record, jvmtiEnv *jvmti, FILE* fp) {
|
||||
if (record != NULL && record->methods != NULL) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < record->numstackframes; i++) {
|
||||
jvmtiError err;
|
||||
char* method_name = NULL;
|
||||
char* class_name = NULL;
|
||||
char* method_signature = NULL;
|
||||
char* class_signature = NULL;
|
||||
char* generic_ptr_method = NULL;
|
||||
char* generic_ptr_class = NULL;
|
||||
jmethodID id;
|
||||
jclass declaringclassptr;
|
||||
id = record->methods[i];
|
||||
|
||||
err = (*jvmti)->GetMethodDeclaringClass(jvmti, id,
|
||||
&declaringclassptr);
|
||||
check_jvmti_error(jvmti, err, "get method declaring class");
|
||||
|
||||
err = (*jvmti)->GetClassSignature(jvmti, declaringclassptr,
|
||||
&class_signature, &generic_ptr_class);
|
||||
check_jvmti_error(jvmti, err, "get class signature");
|
||||
|
||||
err = (*jvmti)->GetMethodName(jvmti, id, &method_name,
|
||||
&method_signature, &generic_ptr_method);
|
||||
check_jvmti_error(jvmti, err, "get method name");
|
||||
|
||||
fprintf(fp, "%s::%s %s %s @%d\n", class_signature, method_name,
|
||||
method_signature,
|
||||
generic_ptr_method == NULL ? "" : generic_ptr_method,
|
||||
record->bcis[i]);
|
||||
|
||||
if (method_name != NULL) {
|
||||
err = (*jvmti)->Deallocate(jvmti, (unsigned char*)method_name);
|
||||
check_jvmti_error(jvmti, err, "deallocate method_name");
|
||||
}
|
||||
if (method_signature != NULL) {
|
||||
err = (*jvmti)->Deallocate(jvmti,
|
||||
(unsigned char*)method_signature);
|
||||
check_jvmti_error(jvmti, err, "deallocate method_signature");
|
||||
}
|
||||
if (generic_ptr_method != NULL) {
|
||||
err = (*jvmti)->Deallocate(jvmti,
|
||||
(unsigned char*)generic_ptr_method);
|
||||
check_jvmti_error(jvmti, err, "deallocate generic_ptr_method");
|
||||
}
|
||||
if (class_name != NULL) {
|
||||
err = (*jvmti)->Deallocate(jvmti, (unsigned char*)class_name);
|
||||
check_jvmti_error(jvmti, err, "deallocate class_name");
|
||||
}
|
||||
if (class_signature != NULL) {
|
||||
err = (*jvmti)->Deallocate(jvmti,
|
||||
(unsigned char*)class_signature);
|
||||
check_jvmti_error(jvmti, err, "deallocate class_signature");
|
||||
}
|
||||
if (generic_ptr_class != NULL) {
|
||||
err = (*jvmti)->Deallocate(jvmti,
|
||||
(unsigned char*)generic_ptr_class);
|
||||
check_jvmti_error(jvmti, err, "deallocate generic_ptr_class");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* print a jvmtiCompiledMethodLoadInlineRecord */
|
||||
void
|
||||
print_inline_info_record(jvmtiCompiledMethodLoadInlineRecord* record,
|
||||
jvmtiEnv *jvmti, FILE* fp) {
|
||||
|
||||
if (record != NULL && record->pcinfo != NULL) {
|
||||
int numpcs = record->numpcs;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < numpcs; i++) {
|
||||
PCStackInfo pcrecord = (record->pcinfo[i]);
|
||||
fprintf(fp, "PcDescriptor(pc=%p):\n", pcrecord.pc);
|
||||
print_stack_frames(&pcrecord, jvmti, fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* decode kind of CompiledMethodLoadRecord and print */
|
||||
void
|
||||
print_records(jvmtiCompiledMethodLoadRecordHeader* list, jvmtiEnv *jvmti,
|
||||
FILE* fp)
|
||||
{
|
||||
jvmtiCompiledMethodLoadRecordHeader* curr = list;
|
||||
fprintf(fp, "\nPrinting PC Descriptors\n\n");
|
||||
while (curr != NULL) {
|
||||
switch (curr->kind) {
|
||||
case JVMTI_CMLR_DUMMY:
|
||||
print_dummy_record((jvmtiCompiledMethodLoadDummyRecord *)curr,
|
||||
jvmti, fp);
|
||||
break;
|
||||
|
||||
case JVMTI_CMLR_INLINE_INFO:
|
||||
print_inline_info_record(
|
||||
(jvmtiCompiledMethodLoadInlineRecord *)curr, jvmti, fp);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(fp, "Warning: unrecognized record: kind=%d\n", curr->kind);
|
||||
break;
|
||||
}
|
||||
|
||||
curr = (jvmtiCompiledMethodLoadRecordHeader *)curr->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_COMPILED_METHOD_LOAD */
|
||||
void JNICALL
|
||||
compiled_method_load(jvmtiEnv *jvmti, jmethodID method, jint code_size,
|
||||
const void* code_addr, jint map_length, const jvmtiAddrLocationMap* map,
|
||||
const void* compile_info)
|
||||
{
|
||||
jvmtiError err;
|
||||
char* name = NULL;
|
||||
char* signature = NULL;
|
||||
char* generic_ptr = NULL;
|
||||
jvmtiCompiledMethodLoadRecordHeader* pcs;
|
||||
|
||||
err = (*jvmti)->RawMonitorEnter(jvmti, lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor enter");
|
||||
|
||||
err = (*jvmti)->GetMethodName(jvmti, method, &name, &signature,
|
||||
&generic_ptr);
|
||||
check_jvmti_error(jvmti, err, "get method name");
|
||||
|
||||
fprintf(fp, "\nCompiled method load event\n");
|
||||
fprintf(fp, "Method name %s %s %s\n\n", name, signature,
|
||||
generic_ptr == NULL ? "" : generic_ptr);
|
||||
pcs = (jvmtiCompiledMethodLoadRecordHeader *)compile_info;
|
||||
if (pcs != NULL) {
|
||||
print_records(pcs, jvmti, fp);
|
||||
}
|
||||
|
||||
if (name != NULL) {
|
||||
err = (*jvmti)->Deallocate(jvmti, (unsigned char*)name);
|
||||
check_jvmti_error(jvmti, err, "deallocate name");
|
||||
}
|
||||
if (signature != NULL) {
|
||||
err = (*jvmti)->Deallocate(jvmti, (unsigned char*)signature);
|
||||
check_jvmti_error(jvmti, err, "deallocate signature");
|
||||
}
|
||||
if (generic_ptr != NULL) {
|
||||
err = (*jvmti)->Deallocate(jvmti, (unsigned char*)generic_ptr);
|
||||
check_jvmti_error(jvmti, err, "deallocate generic_ptr");
|
||||
}
|
||||
|
||||
err = (*jvmti)->RawMonitorExit(jvmti, lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor exit");
|
||||
}
|
||||
|
||||
/* Agent_OnLoad() is called first, we prepare for a COMPILED_METHOD_LOAD
|
||||
* event here.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jint rc;
|
||||
jvmtiError err;
|
||||
jvmtiCapabilities capabilities;
|
||||
jvmtiEventCallbacks callbacks;
|
||||
|
||||
fp = fopen(OUTPUT_FILE, "w");
|
||||
if (fp == NULL) {
|
||||
fatal_error("ERROR: %s: Unable to create output file\n", OUTPUT_FILE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get JVMTI environment */
|
||||
rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION);
|
||||
if (rc != JNI_OK) {
|
||||
fatal_error(
|
||||
"ERROR: Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add JVMTI capabilities */
|
||||
memset(&capabilities,0, sizeof(capabilities));
|
||||
capabilities.can_generate_compiled_method_load_events = 1;
|
||||
err = (*jvmti)->AddCapabilities(jvmti, &capabilities);
|
||||
check_jvmti_error(jvmti, err, "add capabilities");
|
||||
|
||||
/* set JVMTI callbacks for events */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.CompiledMethodLoad = &compiled_method_load;
|
||||
err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
|
||||
check_jvmti_error(jvmti, err, "set event callbacks");
|
||||
|
||||
/* enable JVMTI events */
|
||||
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
|
||||
/* create coordination monitor */
|
||||
err = (*jvmti)->CreateRawMonitor(jvmti, "agent lock", &lock);
|
||||
check_jvmti_error(jvmti, err, "create raw monitor");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Sample GNU Makefile for building JVMTI Demo compiledMethodLoad
|
||||
#
|
||||
# Example uses:
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparc]
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparcv9]
|
||||
# gnumake JDK=<java_home> OSNAME=linux [OPT=true]
|
||||
# gnumake JDK=<java_home> OSNAME=win32 [OPT=true]
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Source lists
|
||||
LIBNAME=compiledMethodLoad
|
||||
SOURCES=compiledMethodLoad.c ../agent_util/agent_util.c
|
||||
|
||||
# Solaris Studio C Compiler Version 12.4
|
||||
ifeq ($(OSNAME), solaris)
|
||||
# Sun Solaris Compiler options needed
|
||||
COMMON_FLAGS=-mt -KPIC
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -Xa -v -xc99=%none
|
||||
# Check LIBARCH for any special compiler options
|
||||
LIBARCH=$(shell uname -p)
|
||||
ifeq ($(LIBARCH), sparc)
|
||||
COMMON_FLAGS+=-xarch=v8 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(LIBARCH), sparcv9)
|
||||
COMMON_FLAGS+=-xarch=v9 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-xO2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-z defs -ztext
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES= -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -G -o $@
|
||||
endif
|
||||
|
||||
# Linux GNU C Compiler
|
||||
ifeq ($(OSNAME), linux)
|
||||
# GNU Compiler options needed to build it
|
||||
COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-O2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -shared -o $@
|
||||
endif
|
||||
|
||||
# Windows Microsoft C/C++ Optimizing Compiler Version 12
|
||||
ifeq ($(OSNAME), win32)
|
||||
CC=cl
|
||||
# Compiler options needed to build it
|
||||
COMMON_FLAGS=-Gy -DWIN32
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+=-W0 -WX
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS= -Ox -Op -Zi $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS= -Od -Zi $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.obj)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=$(LIBNAME).dll
|
||||
LDFLAGS=
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=
|
||||
# Building a shared library
|
||||
LINK_SHARED=link -dll -out:$@
|
||||
endif
|
||||
|
||||
# Common -I options
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../agent_util
|
||||
CFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME)
|
||||
|
||||
# Default rule
|
||||
all: $(LIBRARY)
|
||||
|
||||
# Build native library
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
|
||||
|
||||
# Cleanup the built bits
|
||||
clean:
|
||||
rm -f $(LIBRARY) $(OBJECTS)
|
||||
|
||||
# Simple tester
|
||||
test: all
|
||||
LD_LIBRARY_PATH=`pwd` $(JDK)/bin/java -agentlib:$(LIBNAME) -version
|
||||
|
||||
# Compilation rule only needed on Windows
|
||||
ifeq ($(OSNAME), win32)
|
||||
%.obj: %.c
|
||||
$(COMPILE.c) $<
|
||||
endif
|
||||
|
@ -1,54 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
gctest
|
||||
|
||||
This agent library can be used to track garbage collection events.
|
||||
|
||||
You can use this agent library as follows:
|
||||
|
||||
java -agentlib:gctest ...
|
||||
|
||||
To get help on the available options try:
|
||||
|
||||
java -agentlib:gctest=help
|
||||
|
||||
See ${JAVA_HOME}/demo/jvmti/index.html for help running and building agents.
|
||||
|
||||
The Events JVMTI_EVENT_GARBAGE_COLLECTION_START,
|
||||
JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, and JVMTI_EVENT_OBJECT_FREE
|
||||
all have limitations as to what can be called directly inside the
|
||||
agent callback functions (e.g. no JNI calls are allowed, and limited
|
||||
interface calls can be made). However, by using raw monitors and a separate
|
||||
watcher thread, this agent demonstrates how these limitations can be
|
||||
easily avoided, allowing the watcher thread to do just about anything
|
||||
after the JVMTI_EVENT_GARBAGE_COLLECTION_FINISH event.
|
||||
|
@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/* Example of using JVMTI_EVENT_GARBAGE_COLLECTION_START and
|
||||
* JVMTI_EVENT_GARBAGE_COLLECTION_FINISH events.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
/* For stdout_message(), fatal_error(), and check_jvmti_error() */
|
||||
#include "agent_util.h"
|
||||
|
||||
/* Global static data */
|
||||
static jvmtiEnv *jvmti;
|
||||
static int gc_count;
|
||||
static jrawMonitorID lock;
|
||||
|
||||
/* Worker thread that waits for garbage collections */
|
||||
static void JNICALL
|
||||
worker(jvmtiEnv* jvmti, JNIEnv* jni, void *p)
|
||||
{
|
||||
jvmtiError err;
|
||||
|
||||
stdout_message("GC worker started...\n");
|
||||
|
||||
for (;;) {
|
||||
err = (*jvmti)->RawMonitorEnter(jvmti, lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor enter");
|
||||
while (gc_count == 0) {
|
||||
err = (*jvmti)->RawMonitorWait(jvmti, lock, 0);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
err = (*jvmti)->RawMonitorExit(jvmti, lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor wait");
|
||||
return;
|
||||
}
|
||||
}
|
||||
gc_count = 0;
|
||||
|
||||
err = (*jvmti)->RawMonitorExit(jvmti, lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor exit");
|
||||
|
||||
/* Perform arbitrary JVMTI/JNI work here to do post-GC cleanup */
|
||||
stdout_message("post-GarbageCollectionFinish actions...\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Creates a new jthread */
|
||||
static jthread
|
||||
alloc_thread(JNIEnv *env)
|
||||
{
|
||||
jclass thrClass;
|
||||
jmethodID cid;
|
||||
jthread res;
|
||||
|
||||
thrClass = (*env)->FindClass(env, "java/lang/Thread");
|
||||
if ( thrClass == NULL ) {
|
||||
fatal_error("Cannot find Thread class\n");
|
||||
}
|
||||
cid = (*env)->GetMethodID(env, thrClass, "<init>", "()V");
|
||||
if ( cid == NULL ) {
|
||||
fatal_error("Cannot find Thread constructor method\n");
|
||||
}
|
||||
res = (*env)->NewObject(env, thrClass, cid);
|
||||
if ( res == NULL ) {
|
||||
fatal_error("Cannot create new Thread object\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_INIT */
|
||||
static void JNICALL
|
||||
vm_init(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
jvmtiError err;
|
||||
|
||||
stdout_message("VMInit...\n");
|
||||
|
||||
err = (*jvmti)->RunAgentThread(jvmti, alloc_thread(env), &worker, NULL,
|
||||
JVMTI_THREAD_MAX_PRIORITY);
|
||||
check_jvmti_error(jvmti, err, "running agent thread");
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_GARBAGE_COLLECTION_START */
|
||||
static void JNICALL
|
||||
gc_start(jvmtiEnv* jvmti_env)
|
||||
{
|
||||
stdout_message("GarbageCollectionStart...\n");
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_GARBAGE_COLLECTION_FINISH */
|
||||
static void JNICALL
|
||||
gc_finish(jvmtiEnv* jvmti_env)
|
||||
{
|
||||
jvmtiError err;
|
||||
|
||||
stdout_message("GarbageCollectionFinish...\n");
|
||||
|
||||
err = (*jvmti)->RawMonitorEnter(jvmti, lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor enter");
|
||||
gc_count++;
|
||||
err = (*jvmti)->RawMonitorNotify(jvmti, lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor notify");
|
||||
err = (*jvmti)->RawMonitorExit(jvmti, lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor exit");
|
||||
}
|
||||
|
||||
/* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jint rc;
|
||||
jvmtiError err;
|
||||
jvmtiCapabilities capabilities;
|
||||
jvmtiEventCallbacks callbacks;
|
||||
|
||||
/* Get JVMTI environment */
|
||||
rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION);
|
||||
if (rc != JNI_OK) {
|
||||
fatal_error("ERROR: Unable to create jvmtiEnv, rc=%d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get/Add JVMTI capabilities */
|
||||
(void)memset(&capabilities, 0, sizeof(capabilities));
|
||||
capabilities.can_generate_garbage_collection_events = 1;
|
||||
err = (*jvmti)->AddCapabilities(jvmti, &capabilities);
|
||||
check_jvmti_error(jvmti, err, "add capabilities");
|
||||
|
||||
/* Set callbacks and enable event notifications */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.VMInit = &vm_init;
|
||||
callbacks.GarbageCollectionStart = &gc_start;
|
||||
callbacks.GarbageCollectionFinish = &gc_finish;
|
||||
err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
|
||||
check_jvmti_error(jvmti, err, "set event callbacks");
|
||||
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_INIT, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notification");
|
||||
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notification");
|
||||
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notification");
|
||||
|
||||
/* Create the necessary raw monitor */
|
||||
err = (*jvmti)->CreateRawMonitor(jvmti, "lock", &lock);
|
||||
check_jvmti_error(jvmti, err, "create raw monitor");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Sample GNU Makefile for building JVMTI Demo gctest
|
||||
#
|
||||
# Example uses:
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparc]
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparcv9]
|
||||
# gnumake JDK=<java_home> OSNAME=linux [OPT=true]
|
||||
# gnumake JDK=<java_home> OSNAME=win32 [OPT=true]
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Source lists
|
||||
LIBNAME=gctest
|
||||
SOURCES=gctest.c ../agent_util/agent_util.c
|
||||
|
||||
# Solaris Studio C Compiler Version 12.4
|
||||
ifeq ($(OSNAME), solaris)
|
||||
# Sun Solaris Compiler options needed
|
||||
COMMON_FLAGS=-mt -KPIC
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -Xa -v -xc99=%none
|
||||
# Check LIBARCH for any special compiler options
|
||||
LIBARCH=$(shell uname -p)
|
||||
ifeq ($(LIBARCH), sparc)
|
||||
COMMON_FLAGS+=-xarch=v8 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(LIBARCH), sparcv9)
|
||||
COMMON_FLAGS+=-xarch=v9 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-xO2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-z defs -ztext
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES= -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -G -o $@
|
||||
endif
|
||||
|
||||
# Linux GNU C Compiler
|
||||
ifeq ($(OSNAME), linux)
|
||||
# GNU Compiler options needed to build it
|
||||
COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-O2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -shared -o $@
|
||||
endif
|
||||
|
||||
# Windows Microsoft C/C++ Optimizing Compiler Version 12
|
||||
ifeq ($(OSNAME), win32)
|
||||
CC=cl
|
||||
# Compiler options needed to build it
|
||||
COMMON_FLAGS=-Gy -DWIN32
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+=-W0 -WX
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS= -Ox -Op -Zi $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS= -Od -Zi $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.obj)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=$(LIBNAME).dll
|
||||
LDFLAGS=
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=
|
||||
# Building a shared library
|
||||
LINK_SHARED=link -dll -out:$@
|
||||
endif
|
||||
|
||||
# Common -I options
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../agent_util
|
||||
CFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME)
|
||||
|
||||
# Default rule
|
||||
all: $(LIBRARY)
|
||||
|
||||
# Build native library
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
|
||||
|
||||
# Cleanup the built bits
|
||||
clean:
|
||||
rm -f $(LIBRARY) $(OBJECTS)
|
||||
|
||||
# Simple tester
|
||||
test: all
|
||||
LD_LIBRARY_PATH=`pwd` $(JDK)/bin/java -agentlib:$(LIBNAME) -version
|
||||
|
||||
# Compilation rule only needed on Windows
|
||||
ifeq ($(OSNAME), win32)
|
||||
%.obj: %.c
|
||||
$(COMPILE.c) $<
|
||||
endif
|
||||
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Java class to hold static methods which will be called in byte code
|
||||
* injections of all class files.
|
||||
*/
|
||||
|
||||
public class HeapTracker {
|
||||
|
||||
private static int engaged = 0;
|
||||
|
||||
private static native void _newobj(Object thread, Object o);
|
||||
public static void newobj(Object o)
|
||||
{
|
||||
if ( engaged != 0 ) {
|
||||
_newobj(Thread.currentThread(), o);
|
||||
}
|
||||
}
|
||||
|
||||
private static native void _newarr(Object thread, Object a);
|
||||
public static void newarr(Object a)
|
||||
{
|
||||
if ( engaged != 0 ) {
|
||||
_newarr(Thread.currentThread(), a);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
heapTracker
|
||||
|
||||
This agent library can be used to track object allocations.
|
||||
It uses the same java_crw_demo library used by HPROF to do BCI
|
||||
on all classfiles loaded into the Virtual Machine.
|
||||
|
||||
You can use this agent library as follows:
|
||||
|
||||
java -agentlib:heapTracker ...
|
||||
|
||||
To get help on the available options try:
|
||||
|
||||
java -agentlib:heapTracker=help
|
||||
|
||||
See ${JAVA_HOME}/demo/jvmti/index.html for help running and building agents.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/* Primary heapTracker #include file, should be included by most if not
|
||||
* all heapTracker source files. Gives access to the global data structure
|
||||
* and all global macros.
|
||||
*/
|
||||
|
||||
#ifndef HEAP_TRACKER_H
|
||||
#define HEAP_TRACKER_H
|
||||
|
||||
/* Standard C functions used throughout. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* General JVM/Java functions, types and macros. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
/* Utility functions */
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
#endif
|
@ -1,163 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Sample GNU Makefile for building JVMTI Demo heapTracker
|
||||
#
|
||||
# Example uses:
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparc]
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparcv9]
|
||||
# gnumake JDK=<java_home> OSNAME=linux [OPT=true]
|
||||
# gnumake JDK=<java_home> OSNAME=win32 [OPT=true]
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Source lists
|
||||
LIBNAME=heapTracker
|
||||
SOURCES=heapTracker.c ../agent_util/agent_util.c
|
||||
JAVA_SOURCES=HeapTracker.java
|
||||
|
||||
# Name of jar file that needs to be created
|
||||
JARFILE=heapTracker.jar
|
||||
|
||||
# Solaris Studio C Compiler Version 12.4
|
||||
ifeq ($(OSNAME), solaris)
|
||||
# Sun Solaris Compiler options needed
|
||||
COMMON_FLAGS=-mt -KPIC
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -Xa -v -xc99=%none
|
||||
# Check LIBARCH for any special compiler options
|
||||
LIBARCH=$(shell uname -p)
|
||||
ifeq ($(LIBARCH), sparc)
|
||||
COMMON_FLAGS+=-xarch=v8 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(LIBARCH), sparcv9)
|
||||
COMMON_FLAGS+=-xarch=v9 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-xO2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-z defs -ztext
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-L $(JDK)/jre/lib/$(LIBARCH) -ljava_crw_demo -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -G -o $@
|
||||
endif
|
||||
|
||||
# Linux GNU C Compiler
|
||||
ifeq ($(OSNAME), linux)
|
||||
# GNU Compiler options needed to build it
|
||||
COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-O2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-L $(JDK)/jre/lib/$(LIBARCH) -ljava_crw_demo -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -shared -o $@
|
||||
endif
|
||||
|
||||
# Windows Microsoft C/C++ Optimizing Compiler Version 12
|
||||
ifeq ($(OSNAME), win32)
|
||||
CC=cl
|
||||
# Compiler options needed to build it
|
||||
COMMON_FLAGS=-Gy -DWIN32
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+=-W0 -WX
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS= -Ox -Op -Zi $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS= -Od -Zi $(COMMON_FLAGS)
|
||||
endif
|
||||
# Sources need java_crw_demo
|
||||
SOURCES += ../java_crw_demo/java_crw_demo.c
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.obj)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=$(LIBNAME).dll
|
||||
LDFLAGS=
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=$(JDK)/
|
||||
# Building a shared library
|
||||
LINK_SHARED=link -dll -out:$@
|
||||
endif
|
||||
|
||||
# Common -I options
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../agent_util
|
||||
CFLAGS += -I../java_crw_demo
|
||||
CFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME)
|
||||
|
||||
# Default rule (build both native library and jar file)
|
||||
all: $(LIBRARY) $(JARFILE)
|
||||
|
||||
# Build native library
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
|
||||
|
||||
# Build jar file
|
||||
$(JARFILE): $(JAVA_SOURCES)
|
||||
rm -f -r classes
|
||||
mkdir -p classes
|
||||
$(JDK)/bin/javac -d classes $(JAVA_SOURCES)
|
||||
(cd classes; $(JDK)/bin/jar cf ../$@ *)
|
||||
|
||||
# Cleanup the built bits
|
||||
clean:
|
||||
rm -f -r classes
|
||||
rm -f $(LIBRARY) $(JARFILE) $(OBJECTS)
|
||||
|
||||
# Simple tester
|
||||
test: all
|
||||
LD_LIBRARY_PATH=. $(JDK)/bin/java -agentlib:$(LIBNAME) -Xbootclasspath/a:./$(JARFILE) -version
|
||||
|
||||
# Compilation rule only needed on Windows
|
||||
ifeq ($(OSNAME), win32)
|
||||
%.obj: %.c
|
||||
$(COMPILE.c) $<
|
||||
endif
|
||||
|
@ -1,56 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
heapViewer
|
||||
|
||||
This agent library demonstrates how to get an easy view of the
|
||||
heap in terms of total object count and space used.
|
||||
It uses GetLoadedClasses(), SetTag(), and IterateThroughHeap()
|
||||
to count up all the objects of all the current loaded classes.
|
||||
The heap dump will happen at the event JVMTI_EVENT_VM_DEATH, or the
|
||||
event JVMTI_EVENT_DATA_DUMP_REQUEST.
|
||||
|
||||
It also demonstrates some more robust agent error handling using
|
||||
GetErrorName(),
|
||||
|
||||
Using the heap iterate functions, lots of statistics can be generated
|
||||
without resorting to using Byte Code Instrumentation (BCI).
|
||||
|
||||
You can use this agent library as follows:
|
||||
|
||||
java -agentlib:heapViewer ...
|
||||
|
||||
To get help on the available options try:
|
||||
|
||||
java -agentlib:heapViewer=help
|
||||
|
||||
See ${JAVA_HOME}/demo/jvmti/index.html for help running and building agents.
|
||||
|
@ -1,288 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
/* Global static data */
|
||||
typedef struct {
|
||||
jboolean vmDeathCalled;
|
||||
jboolean dumpInProgress;
|
||||
jrawMonitorID lock;
|
||||
} GlobalData;
|
||||
static GlobalData globalData, *gdata = &globalData;
|
||||
|
||||
/* Typedef to hold class details */
|
||||
typedef struct {
|
||||
char *signature;
|
||||
int count;
|
||||
int space;
|
||||
} ClassDetails;
|
||||
|
||||
/* Enter agent monitor protected section */
|
||||
static void
|
||||
enterAgentMonitor(jvmtiEnv *jvmti)
|
||||
{
|
||||
jvmtiError err;
|
||||
|
||||
err = (*jvmti)->RawMonitorEnter(jvmti, gdata->lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor enter");
|
||||
}
|
||||
|
||||
/* Exit agent monitor protected section */
|
||||
static void
|
||||
exitAgentMonitor(jvmtiEnv *jvmti)
|
||||
{
|
||||
jvmtiError err;
|
||||
|
||||
err = (*jvmti)->RawMonitorExit(jvmti, gdata->lock);
|
||||
check_jvmti_error(jvmti, err, "raw monitor exit");
|
||||
}
|
||||
|
||||
/* Heap object callback */
|
||||
static jint JNICALL
|
||||
cbHeapObject(jlong class_tag, jlong size, jlong* tag_ptr, jint length,
|
||||
void* user_data)
|
||||
{
|
||||
if ( class_tag != (jlong)0 ) {
|
||||
ClassDetails *d;
|
||||
|
||||
d = (ClassDetails*)(void*)(ptrdiff_t)class_tag;
|
||||
(*((jint*)(user_data)))++;
|
||||
d->count++;
|
||||
d->space += (int)size;
|
||||
}
|
||||
return JVMTI_VISIT_OBJECTS;
|
||||
}
|
||||
|
||||
/* Compare two ClassDetails */
|
||||
static int
|
||||
compareDetails(const void *p1, const void *p2)
|
||||
{
|
||||
return ((ClassDetails*)p2)->space - ((ClassDetails*)p1)->space;
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_DATA_DUMP_REQUEST (Ctrl-\ or at exit) */
|
||||
static void JNICALL
|
||||
dataDumpRequest(jvmtiEnv *jvmti)
|
||||
{
|
||||
enterAgentMonitor(jvmti); {
|
||||
if ( !gdata->vmDeathCalled && !gdata->dumpInProgress ) {
|
||||
jvmtiHeapCallbacks heapCallbacks;
|
||||
ClassDetails *details;
|
||||
jvmtiError err;
|
||||
jclass *classes;
|
||||
jint totalCount;
|
||||
jint count;
|
||||
jint i;
|
||||
|
||||
gdata->dumpInProgress = JNI_TRUE;
|
||||
|
||||
/* Get all the loaded classes */
|
||||
err = (*jvmti)->GetLoadedClasses(jvmti, &count, &classes);
|
||||
check_jvmti_error(jvmti, err, "get loaded classes");
|
||||
|
||||
/* Setup an area to hold details about these classes */
|
||||
details = (ClassDetails*)calloc(sizeof(ClassDetails), count);
|
||||
if ( details == NULL ) {
|
||||
fatal_error("ERROR: Ran out of malloc space\n");
|
||||
}
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
char *sig;
|
||||
|
||||
/* Get and save the class signature */
|
||||
err = (*jvmti)->GetClassSignature(jvmti, classes[i], &sig, NULL);
|
||||
check_jvmti_error(jvmti, err, "get class signature");
|
||||
if ( sig == NULL ) {
|
||||
fatal_error("ERROR: No class signature found\n");
|
||||
}
|
||||
details[i].signature = strdup(sig);
|
||||
deallocate(jvmti, sig);
|
||||
|
||||
/* Tag this jclass */
|
||||
err = (*jvmti)->SetTag(jvmti, classes[i],
|
||||
(jlong)(ptrdiff_t)(void*)(&details[i]));
|
||||
check_jvmti_error(jvmti, err, "set object tag");
|
||||
}
|
||||
|
||||
/* Iterate through the heap and count up uses of jclass */
|
||||
(void)memset(&heapCallbacks, 0, sizeof(heapCallbacks));
|
||||
heapCallbacks.heap_iteration_callback = &cbHeapObject;
|
||||
totalCount = 0;
|
||||
err = (*jvmti)->IterateThroughHeap(jvmti,
|
||||
JVMTI_HEAP_FILTER_CLASS_UNTAGGED, NULL,
|
||||
&heapCallbacks, (const void *)&totalCount);
|
||||
check_jvmti_error(jvmti, err, "iterate through heap");
|
||||
|
||||
/* Remove tags */
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
/* Un-Tag this jclass */
|
||||
err = (*jvmti)->SetTag(jvmti, classes[i], (jlong)0);
|
||||
check_jvmti_error(jvmti, err, "set object tag");
|
||||
}
|
||||
|
||||
/* Sort details by space used */
|
||||
qsort(details, count, sizeof(ClassDetails), &compareDetails);
|
||||
|
||||
/* Print out sorted table */
|
||||
stdout_message("Heap View, Total of %d objects found.\n\n",
|
||||
totalCount);
|
||||
|
||||
stdout_message("Space Count Class Signature\n");
|
||||
stdout_message("---------- ---------- ----------------------\n");
|
||||
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
if ( details[i].space == 0 || i > 20 ) {
|
||||
break;
|
||||
}
|
||||
stdout_message("%10d %10d %s\n",
|
||||
details[i].space, details[i].count, details[i].signature);
|
||||
}
|
||||
stdout_message("---------- ---------- ----------------------\n\n");
|
||||
|
||||
/* Free up all allocated space */
|
||||
deallocate(jvmti, classes);
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
if ( details[i].signature != NULL ) {
|
||||
free(details[i].signature);
|
||||
}
|
||||
}
|
||||
free(details);
|
||||
|
||||
gdata->dumpInProgress = JNI_FALSE;
|
||||
}
|
||||
} exitAgentMonitor(jvmti);
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_INIT */
|
||||
static void JNICALL
|
||||
vmInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
enterAgentMonitor(jvmti); {
|
||||
jvmtiError err;
|
||||
|
||||
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_DATA_DUMP_REQUEST, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notification");
|
||||
} exitAgentMonitor(jvmti);
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_DEATH */
|
||||
static void JNICALL
|
||||
vmDeath(jvmtiEnv *jvmti, JNIEnv *env)
|
||||
{
|
||||
jvmtiError err;
|
||||
|
||||
/* Make sure everything has been garbage collected */
|
||||
err = (*jvmti)->ForceGarbageCollection(jvmti);
|
||||
check_jvmti_error(jvmti, err, "force garbage collection");
|
||||
|
||||
/* Disable events and dump the heap information */
|
||||
enterAgentMonitor(jvmti); {
|
||||
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_DISABLE,
|
||||
JVMTI_EVENT_DATA_DUMP_REQUEST, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notification");
|
||||
|
||||
dataDumpRequest(jvmti);
|
||||
|
||||
gdata->vmDeathCalled = JNI_TRUE;
|
||||
} exitAgentMonitor(jvmti);
|
||||
}
|
||||
|
||||
/* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jint rc;
|
||||
jvmtiError err;
|
||||
jvmtiCapabilities capabilities;
|
||||
jvmtiEventCallbacks callbacks;
|
||||
jvmtiEnv *jvmti;
|
||||
|
||||
/* Get JVMTI environment */
|
||||
jvmti = NULL;
|
||||
rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION);
|
||||
if (rc != JNI_OK) {
|
||||
fatal_error("ERROR: Unable to create jvmtiEnv, error=%d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
if ( jvmti == NULL ) {
|
||||
fatal_error("ERROR: No jvmtiEnv* returned from GetEnv\n");
|
||||
}
|
||||
|
||||
/* Get/Add JVMTI capabilities */
|
||||
(void)memset(&capabilities, 0, sizeof(capabilities));
|
||||
capabilities.can_tag_objects = 1;
|
||||
capabilities.can_generate_garbage_collection_events = 1;
|
||||
err = (*jvmti)->AddCapabilities(jvmti, &capabilities);
|
||||
check_jvmti_error(jvmti, err, "add capabilities");
|
||||
|
||||
/* Create the raw monitor */
|
||||
err = (*jvmti)->CreateRawMonitor(jvmti, "agent lock", &(gdata->lock));
|
||||
check_jvmti_error(jvmti, err, "create raw monitor");
|
||||
|
||||
/* Set callbacks and enable event notifications */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.VMInit = &vmInit;
|
||||
callbacks.VMDeath = &vmDeath;
|
||||
callbacks.DataDumpRequest = &dataDumpRequest;
|
||||
err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
|
||||
check_jvmti_error(jvmti, err, "set event callbacks");
|
||||
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_INIT, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notifications");
|
||||
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_DEATH, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notifications");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Sample GNU Makefile for building JVMTI Demo heapViewer
|
||||
#
|
||||
# Example uses:
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparc]
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparcv9]
|
||||
# gnumake JDK=<java_home> OSNAME=linux [OPT=true]
|
||||
# gnumake JDK=<java_home> OSNAME=win32 [OPT=true]
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Source lists
|
||||
LIBNAME=heapViewer
|
||||
SOURCES=heapViewer.c ../agent_util/agent_util.c
|
||||
|
||||
# Solaris Studio C Compiler Version 12.4
|
||||
ifeq ($(OSNAME), solaris)
|
||||
# Sun Solaris Compiler options needed
|
||||
COMMON_FLAGS=-mt -KPIC
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -Xa -v -xc99=%none
|
||||
# Check LIBARCH for any special compiler options
|
||||
LIBARCH=$(shell uname -p)
|
||||
ifeq ($(LIBARCH), sparc)
|
||||
COMMON_FLAGS+=-xarch=v8 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(LIBARCH), sparcv9)
|
||||
COMMON_FLAGS+=-xarch=v9 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-xO2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-z defs -ztext
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES= -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -G -o $@
|
||||
endif
|
||||
|
||||
# Linux GNU C Compiler
|
||||
ifeq ($(OSNAME), linux)
|
||||
# GNU Compiler options needed to build it
|
||||
COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-O2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -shared -o $@
|
||||
endif
|
||||
|
||||
# Windows Microsoft C/C++ Optimizing Compiler Version 12
|
||||
ifeq ($(OSNAME), win32)
|
||||
CC=cl
|
||||
# Compiler options needed to build it
|
||||
COMMON_FLAGS=-Gy -DWIN32
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+=-W0 -WX
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS= -Ox -Op -Zi $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS= -Od -Zi $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.obj)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=$(LIBNAME).dll
|
||||
LDFLAGS=
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=
|
||||
# Building a shared library
|
||||
LINK_SHARED=link -dll -out:$@
|
||||
endif
|
||||
|
||||
# Common -I options
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME)
|
||||
|
||||
# Default rule
|
||||
all: $(LIBRARY)
|
||||
|
||||
# Build native library
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
|
||||
|
||||
# Cleanup the built bits
|
||||
clean:
|
||||
rm -f $(LIBRARY) $(OBJECTS)
|
||||
|
||||
# Simple tester
|
||||
test: all
|
||||
LD_LIBRARY_PATH=`pwd` $(JDK)/bin/java -agentlib:$(LIBNAME) -version
|
||||
|
||||
# Compilation rule only needed on Windows
|
||||
ifeq ($(OSNAME), win32)
|
||||
%.obj: %.c
|
||||
$(COMPILE.c) $<
|
||||
endif
|
||||
|
@ -1,430 +0,0 @@
|
||||
<html>
|
||||
<head> <title>JVM TI Demonstration Code</title> </head>
|
||||
|
||||
<h1>JVM TI Demonstration Code</h1>
|
||||
|
||||
<p>
|
||||
The
|
||||
Java™ Virtual Machine Tools Interface (JVM TI)
|
||||
is a native tool interface provided in JDK 5.0 and newer.
|
||||
Native libraries that use JVM TI and are loaded into the
|
||||
Java Virtual Machine
|
||||
via the -agentlib, -agentpath, or -Xrun (deprecated) interfaces, are
|
||||
called Agents.
|
||||
<p>
|
||||
<A HREF="http://java.sun.com/j2se/latest/docs/guide/jvmti">JVM TI</A>
|
||||
was designed to work with the
|
||||
Java Native Interface
|
||||
(<A HREF="http://java.sun.com/j2se/latest/docs/guide/jni">JNI</A>),
|
||||
and eventually displace the
|
||||
Java Virtual Machine Debugging Interface
|
||||
(<A HREF="http://java.sun.com/j2se/1.5.0/docs/guide/jpda/jvmdi-spec.html">JVMDI</A>)
|
||||
and the
|
||||
Java Virtual Machine Profiling Interface
|
||||
(<A HREF="http://java.sun.com/j2se/1.5.0/docs/guide/jvmpi/index.html">JVMPI</A>).
|
||||
|
||||
<p>
|
||||
We have created a set of demonstration agents that should
|
||||
help show many of the features and abilities of the
|
||||
interface. This list of demonstration agents will change over time.
|
||||
They are provided as educational tools and as starting
|
||||
points for Java tool development.
|
||||
|
||||
<p>
|
||||
These agents are built with every JDK build and some basic testing is performed
|
||||
on a regular basis, but no extensive testbases currently
|
||||
exist for these agents.
|
||||
Every JDK installation should include all the pre-built binaries and sources for
|
||||
all these agents, just look in the demo/jvmti directory of your JDK.
|
||||
|
||||
|
||||
<h2>Using or Running These Agents</h2>
|
||||
|
||||
<p>
|
||||
Using these agents will require the VM to locate the shared library file
|
||||
before any actual Java code is run.
|
||||
The JDK installation should contain all the agent libraries in
|
||||
the ${JAVA_HOME}/demo/jvmti/<i>agent-name</i>/lib directories.
|
||||
The Solaris 64bit version would be contained in the sparcv9 or amd64
|
||||
subdirectory.
|
||||
If 'java' complains that it can't find the library,
|
||||
you may need to add the directory containing the library into the
|
||||
LD_LIBRARY_PATH environment variable (Unix), or the PATH environment
|
||||
variable (Windows).
|
||||
This is system and platform specific.
|
||||
If you are using 64bit Solaris (e.g. 'java -d64'),
|
||||
you should use LD_LIBRARY_PATH64.
|
||||
Some agents such as the jdwp (debugger backend)
|
||||
are located inside the primary JDK directories and will always be found
|
||||
in those locations.
|
||||
|
||||
<p>
|
||||
The agents that instrument classfiles
|
||||
(i.e. BCI, usually through the java_crw_demo library)
|
||||
such as heapTracker, mtrace, and minst,
|
||||
also need to have the Java classes they use available in the bootclasspath.
|
||||
The agents will make attempts at automatically adding their jar file
|
||||
(e.g. heapTracker.jar, mtrace.jar, or minst.jar) to the bootclasspath
|
||||
with AddToBootstrapClassLoaderSearch from JVM TI at startup
|
||||
(see the agent_util code).
|
||||
This is done by locating this jar file at
|
||||
${JAVA_HOME}/demo/jvmti/<i>agent-name</i>
|
||||
where JAVA_HOME is obtained by calling GetSystemProperty from JVM TI
|
||||
with "java.home".
|
||||
We recognize that this is not ideal, but felt that as just demonstration
|
||||
code it was acceptable.
|
||||
Ideally the agent could find out the actual directory it came from and
|
||||
locate the jar file relative to that location.
|
||||
Our demonstration agents currently do not do this.
|
||||
|
||||
<p>
|
||||
If you choose to modify or change these agents, the above information
|
||||
is important in making everything is found.
|
||||
It is recommended that you change the name of the agent when you
|
||||
modify it to avoid conflicts with the existing demo agents.
|
||||
Or better yet, go to http://jdk.dev.java.net and submit your
|
||||
changes to the agent as an RFE to the JDK.
|
||||
|
||||
|
||||
<h2> Demonstration Agents Available </h2>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<A HREF="versionCheck">versionCheck</A>
|
||||
<br>
|
||||
This is a extremely small agent that does nothing but check the
|
||||
version string supplied in the jvmti.h file, with the version
|
||||
number supplied by the VM at runtime.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="compiledMethodLoad">compiledMethodLoad</A>
|
||||
<br>
|
||||
This is a small agent that traces CompiledMethodLoad events along
|
||||
with the HotSpot specific compile_info parameter.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="mtrace">mtrace</A>
|
||||
<br>
|
||||
This is a small agent that does method tracing.
|
||||
It uses Bytecode Instrumentation (BCI) via the java_crw_demo library.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="minst">minst</A>
|
||||
<br>
|
||||
This is an even smaller agent that does just method entry tracing.
|
||||
It also uses Bytecode Instrumentation (BCI) via the java_crw_demo library,
|
||||
but the instrumentation code is pure Java (no Java native methods used).
|
||||
NOTE: Be sure to check out java.lang.instrument for a way to avoid
|
||||
native code agents completely.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="gctest">gctest</A>
|
||||
<br>
|
||||
This is a small agent that does garbage collection counting.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="heapViewer">heapViewer</A>
|
||||
<br>
|
||||
This is a small agent that does some basic heap inspections.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="heapTracker">heapTracker</A>
|
||||
<br>
|
||||
This is a small agent that does BCI to capture object creation
|
||||
and track them.
|
||||
It uses Bytecode Instrumentation (BCI) via the java_crw_demo library.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="waiters">waiters</A>
|
||||
<br>
|
||||
This is a small agent that gets information about threads
|
||||
waiting on monitors.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<h2>Agent Support</h2>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<A HREF="java_crw_demo">java_crw_demo</A>
|
||||
<br>
|
||||
This is a demo C library that does class file to class file
|
||||
transformations or BCI (Bytecode Instrumentation).
|
||||
It is used by several of the above agents.
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<h2>Native Library Build Hints</h2>
|
||||
|
||||
<p>
|
||||
All libraries loaded into java are assumed to be MT-safe (Multi-thread safe).
|
||||
This means that multiple threads could be executing the code at the same
|
||||
time, and static or global data may need to be placed in critical
|
||||
sections. See the Raw Monitor interfaces for more information.
|
||||
|
||||
<p>
|
||||
All native libraries loaded into the
|
||||
Java Virtual Machine,
|
||||
including Agent libraries,
|
||||
need to be compiled and built in a compatible way.
|
||||
Certain native compilation options or optimizations should be avoided,
|
||||
and some are required.
|
||||
More information on this options is available in the man pages for
|
||||
the various compilers.
|
||||
|
||||
<p>
|
||||
Some native compiler and linker options can create fatal or
|
||||
erroneous behavior when native agent libraries are operating
|
||||
inside the Java Virtual Machine.
|
||||
It would take too many words to describe all the possible issues with all
|
||||
the native compiler options, optimizations, and settings.
|
||||
Here are some recommendations on the basic compiler and linker options
|
||||
we recommend:
|
||||
|
||||
<ul>
|
||||
|
||||
<h3> Solaris </h3>
|
||||
|
||||
<li>
|
||||
On Solaris, using the Sun Studio 11 C compiler,
|
||||
the typical compile and link command lines might look something like:
|
||||
<br>
|
||||
For 32bit SPARC:
|
||||
<br>
|
||||
<code><ul>
|
||||
cc -xO2 -mt -xregs=no%appl -xmemalign=4s -xarch=v8 -KPIC -c <i>*.c</i>
|
||||
<br>
|
||||
cc -mt -xarch=v8 -z defs -ztext -G -o <i>libXXX.so *.o</i> -lc
|
||||
</code></ul>
|
||||
<br>
|
||||
For 64bit SPARC:
|
||||
<br>
|
||||
<code><ul>
|
||||
cc -xO2 -mt -xregs=no%appl -xarch=v9 -KPIC -c <i>*.c</i>
|
||||
<br>
|
||||
cc -mt -xarch=v9 -z defs -ztext -G -o <i>libXXX.so *.o</i> -lc
|
||||
</code></ul>
|
||||
<br>
|
||||
For X86:
|
||||
<br>
|
||||
<code><ul>
|
||||
cc -xO2 -mt -xregs=no%frameptr -KPIC -c <i>*.c</i>
|
||||
<br>
|
||||
cc -mt -z defs -ztext -G -o <i>libXXX.so *.o</i> -lc
|
||||
</code></ul>
|
||||
<br>
|
||||
For AMD64:
|
||||
<br>
|
||||
<code><ul>
|
||||
cc -xO2 -mt -xregs=no%frameptr -xarch=amd64 -KPIC -c <i>*.c</i>
|
||||
<br>
|
||||
cc -mt -xarch=amd64 -z defs -ztext -G -o <i>libXXX.so *.o</i> -lc
|
||||
</code></ul>
|
||||
<br>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Architecture/File Format:
|
||||
For SPARC 32bit use <code>-xarch=v8</code>,
|
||||
for SPARC 64bit use <code>-xarch=v9</code>,
|
||||
for X86 (32-bit)
|
||||
<i>
|
||||
leave the option off or use <code>-xarch=generic</code>
|
||||
</i>,
|
||||
and for AMD64 (64bit) use <code>-xarch=amd64</code>
|
||||
with both C and C++.
|
||||
<br>
|
||||
This is to be specific as to the architecture and the file format
|
||||
of the .o files (and ultimately of the .so).
|
||||
</li>
|
||||
|
||||
<li>
|
||||
MT-Safe, Position Independent: Use <code>-KPIC -mt</code>
|
||||
with both C and C++.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Register usage: For SPARC (both 32bit and 64bit) use
|
||||
<code>-xregs=no%appl</code> and for X86 and AMD64 use <code>-xregs=no%frameptr</code>
|
||||
with both C and C++.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Alignment: For SPARC 32bit use -xmemalign=4s and for SPARC 64bit do NOT use <code>-xmemalign=4</code>
|
||||
with both C and C++.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Dependencies: Use <code>ldd -r <i>LibraryName</i></code>.
|
||||
<br>
|
||||
After the shared library has been built, the utility
|
||||
<code>ldd</code> can be used to verify that all dependent libraries
|
||||
have been satisfied, and all externs can be found.
|
||||
If <code>ldd</code> says anything is missing, it is very likely that the JVM will also
|
||||
be unable to load this library.
|
||||
This usually means that you missed some <code>-l<i>name</i></code>
|
||||
options when building the library, or perhaps forgot a <code>-R path</code>
|
||||
option that tells the library where to look for libraries at runtime.
|
||||
</li>
|
||||
|
||||
<h3> Linux </h3>
|
||||
|
||||
<li>
|
||||
On Linux, using the gcc version 3.2,
|
||||
the typical compile and link command lines might look something like:
|
||||
<br>
|
||||
For X86:
|
||||
<br>
|
||||
<code><ul>
|
||||
gcc -O2 -fPIC -pthread -DLINUX -c <i>*.c</i>
|
||||
<br>
|
||||
gcc -z defs -static-libgcc -shared -o <i>libXXX.so *.o</i> -lc
|
||||
</code></ul>
|
||||
<br>
|
||||
For AMD64:
|
||||
<br>
|
||||
<code><ul>
|
||||
gcc -O2 -fPIC -pthread -DLINUX -D_LP64=1 -c <i>*.c</i>
|
||||
<br>
|
||||
gcc -z defs -static-libgcc -shared -o <i>libXXX.so *.o</i> -lc
|
||||
</code></ul>
|
||||
<br>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
MT-Safe, Position Independent:
|
||||
Use <code>-fPIC -pthread</code>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Agent Demo Code: Needs -DLINUX
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Register Usage: Use <code>-fno-omit-frame-pointer</code>.
|
||||
<br>
|
||||
It is important that these libraries have frame pointer register usage, see the above comments on the Solaris
|
||||
<code>-xregs=no%frameptr</code>
|
||||
option.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Library: Use -static-libgcc.
|
||||
<br>
|
||||
When building the shared library (-shared option), this option
|
||||
allows for maximum portability of the library between different
|
||||
flavors of Linux.
|
||||
The problem we have seen with Linux is that we cannot depend
|
||||
on a compatible shared gcc library existing on all the versions of
|
||||
Linux we can run on.
|
||||
By doing this static link, the version script becomes more
|
||||
important, making sure you don't expose any extern symbols
|
||||
you didn't intend to.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Dependencies: Use <code>ldd -r <i>LibraryName</i></code>.
|
||||
<br>
|
||||
Provides the same checking as Solaris (see above).
|
||||
</li>
|
||||
|
||||
<h3> Windows </h3>
|
||||
|
||||
<li>
|
||||
On Windows and using the Microsoft C++ Compiler Visual Studio .NET 2003,
|
||||
the typical compile and link command lines might look something like:
|
||||
<br>
|
||||
For X86:
|
||||
<br>
|
||||
<code><ul>
|
||||
cl /O1 /MD /D _STATIC_CPPLIB /c <i>*.c</i>
|
||||
<br>
|
||||
link /dll /opt:REF /out:<i>XXX.dll *.obj</i>
|
||||
</code></ul>
|
||||
<br>
|
||||
For AMD64:
|
||||
<br>
|
||||
<code><ul>
|
||||
cl /O1 /MD /D _STATIC_CPPLIB /c <i>*.c</i>
|
||||
<br>
|
||||
link /dll /opt:REF /out:<i>XXX.dll *.obj</i>
|
||||
</code></ul>
|
||||
<br>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Library: Use <code>/opt:REF </code> when building the dll.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
MS DLL Runtime: Use the <code>/MD /D _STATIC_CPPLIB</code> option.
|
||||
<br>
|
||||
This causes your dll to become dependent on just MSVCR*.DLL.
|
||||
The option /D _STATIC_CPPLIB prevents you from becoming dependent on the
|
||||
C++ library MSVCP*.DLL.
|
||||
This is what we use in the JDK, but there are probably many combinations
|
||||
that you could safely use, unfortunately there are many combinations
|
||||
of runtimes that will not work.
|
||||
Check the Microsoft site on proper use of runtimes.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Dependencies: Use VC++ <code>dumpbin /exports</code> and the VC++ "Dependency Walker".
|
||||
<br>
|
||||
Provides dependency information similar to <code>ldd</code>.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>For More Information</h2>
|
||||
|
||||
<p>
|
||||
Remember, the complete source to all these agents is contained in the JDK
|
||||
installations at demo/jvmti.
|
||||
|
||||
<p>
|
||||
For more detailed information on JVM TI, refer to
|
||||
<A HREF="http://java.sun.com/j2se/latest/docs/guide/jvmti">
|
||||
http://java.sun.com/j2se/latest/docs/guide/jvmti.</A>
|
||||
|
||||
<p>
|
||||
More information on using JNI and building native libraries refer to:
|
||||
<A HREF="http://java.sun.com/j2se/latest/docs/guide/jni">
|
||||
http://java.sun.com/j2se/latest/docs/guide/jni</A>.
|
||||
|
||||
<p>
|
||||
Additional information can also be found by doing a search on "jvmti" at
|
||||
<A HREF="http://java.sun.com/j2se">http://java.sun.com/j2se</A>.
|
||||
Various technical articles are also available through this website.
|
||||
And don't forget the
|
||||
Java Tutorials at
|
||||
<A HREF="http://docs.oracle.com/javase/tutorial">http://docs.oracle.com/javase/tutorial</A>
|
||||
for getting a quick start on all the various interfaces.
|
||||
|
||||
<h2>Comments and Feedback</h2>
|
||||
|
||||
<p>
|
||||
Comments regarding JVM TI or on any of these demonstrations should be
|
||||
sent through
|
||||
<A HREF="http://java.sun.com/mail">http://java.sun.com/mail/</A>
|
||||
|
||||
|
||||
|
||||
</html>
|
@ -1,77 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
java_crw_demo Library
|
||||
|
||||
The library java_crw_demo is a small C library that is used by HPROF
|
||||
and other agent libraries to do some very basic bytecode
|
||||
insertion (BCI) of class files. This is not an agent
|
||||
library but a general purpose library that can be used to do some
|
||||
very limited bytecode insertion.
|
||||
|
||||
In the demo sources, look for the use of java_crw_demo.h and
|
||||
the C function java_crw_demo(). The java_crw_demo library is provided
|
||||
as part of the JRE.
|
||||
|
||||
The basic BCI that this library does includes:
|
||||
|
||||
* On entry to the java.lang.Object init method (signature "()V"),
|
||||
a invokestatic call to tclass.obj_init_method(object); is inserted.
|
||||
|
||||
* On any newarray type opcode, immediately following it, the array
|
||||
object is duplicated on the stack and an invokestatic call to
|
||||
tclass.newarray_method(object); is inserted.
|
||||
|
||||
* On entry to all methods, a invokestatic call to
|
||||
tclass.call_method(cnum,mnum); is inserted. The agent can map the
|
||||
two integers (cnum,mnum) to a method in a class, the cnum is the
|
||||
number provided to the java_crw_demo library when the classfile was
|
||||
modified.
|
||||
|
||||
* On return from any method (any return opcode), a invokestatic call to
|
||||
tclass.return_method(cnum,mnum); is inserted.
|
||||
|
||||
Some methods are not modified at all, init methods and finalize methods
|
||||
whose length is 1 will not be modified. Classes that are designated
|
||||
"system" will not have their clinit methods modified. In addition, the
|
||||
method java.lang.Thread.currentThread() is not modified.
|
||||
|
||||
No methods or fields will be added to any class, however new constant
|
||||
pool entries will be added at the end of the original constant pool table.
|
||||
The exception, line, and local variable tables for each method is adjusted
|
||||
for the modification. The bytecodes are compressed to use smaller offsets
|
||||
and the fewest 'wide' opcodes.
|
||||
|
||||
All attempts are made to minimize the number of bytecodes at each insertion
|
||||
site, however, classes with N return opcodes or N newarray opcodes will get
|
||||
N insertions. And only the necessary modification dictated by the input
|
||||
arguments to java_crw_demo are actually made.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,196 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JAVA_CRW_DEMO_H
|
||||
#define JAVA_CRW_DEMO_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This callback is used to notify the caller of a fatal error. */
|
||||
|
||||
typedef void (*FatalErrorHandler)(const char*message, const char*file, int line);
|
||||
|
||||
/* This callback is used to return the method information for a class.
|
||||
* Since the information was already read here, it was useful to
|
||||
* return it here, with no JVMTI phase restrictions.
|
||||
* If the class file does represent a "class" and it has methods, then
|
||||
* this callback will be called with the class number and pointers to
|
||||
* the array of names, array of signatures, and the count of methods.
|
||||
*/
|
||||
|
||||
typedef void (*MethodNumberRegister)(unsigned, const char**, const char**, int);
|
||||
|
||||
/* Class file reader/writer interface. Basic input is a classfile image
|
||||
* and details about what to inject. The output is a new classfile image
|
||||
* that was allocated with malloc(), and should be freed by the caller.
|
||||
*/
|
||||
|
||||
/* Names of external symbols to look for. These are the names that we
|
||||
* try and lookup in the shared library. On Windows 2000, the naming
|
||||
* convention is to prefix a "_" and suffix a "@N" where N is 4 times
|
||||
* the number or arguments supplied.It has 19 args, so 76 = 19*4.
|
||||
* On Windows 2003, Linux, and Solaris, the first name will be
|
||||
* found, on Windows 2000 a second try should find the second name.
|
||||
*
|
||||
* WARNING: If You change the JavaCrwDemo typedef, you MUST change
|
||||
* multiple things in this file, including this name.
|
||||
*/
|
||||
|
||||
#define JAVA_CRW_DEMO_SYMBOLS { "java_crw_demo", "_java_crw_demo@76" }
|
||||
|
||||
/* Typedef needed for type casting in dynamic access situations. */
|
||||
|
||||
typedef void (JNICALL *JavaCrwDemo)(
|
||||
unsigned class_number,
|
||||
const char *name,
|
||||
const unsigned char *file_image,
|
||||
long file_len,
|
||||
int system_class,
|
||||
char* tclass_name,
|
||||
char* tclass_sig,
|
||||
char* call_name,
|
||||
char* call_sig,
|
||||
char* return_name,
|
||||
char* return_sig,
|
||||
char* obj_init_name,
|
||||
char* obj_init_sig,
|
||||
char* newarray_name,
|
||||
char* newarray_sig,
|
||||
unsigned char **pnew_file_image,
|
||||
long *pnew_file_len,
|
||||
FatalErrorHandler fatal_error_handler,
|
||||
MethodNumberRegister mnum_callback
|
||||
);
|
||||
|
||||
/* Function export (should match typedef above) */
|
||||
|
||||
JNIEXPORT void JNICALL java_crw_demo(
|
||||
|
||||
unsigned class_number, /* Caller assigned class number for class */
|
||||
|
||||
const char *name, /* Internal class name, e.g. java/lang/Object */
|
||||
/* (Do not use "java.lang.Object" format) */
|
||||
|
||||
const unsigned char
|
||||
*file_image, /* Pointer to classfile image for this class */
|
||||
|
||||
long file_len, /* Length of the classfile in bytes */
|
||||
|
||||
int system_class, /* Set to 1 if this is a system class */
|
||||
/* (prevents injections into empty */
|
||||
/* <clinit>, finalize, and <init> methods) */
|
||||
|
||||
char* tclass_name, /* Class that has methods we will call at */
|
||||
/* the injection sites (tclass) */
|
||||
|
||||
char* tclass_sig, /* Signature of tclass */
|
||||
/* (Must be "L" + tclass_name + ";") */
|
||||
|
||||
char* call_name, /* Method name in tclass to call at offset 0 */
|
||||
/* for every method */
|
||||
|
||||
char* call_sig, /* Signature of this call_name method */
|
||||
/* (Must be "(II)V") */
|
||||
|
||||
char* return_name, /* Method name in tclass to call at all */
|
||||
/* return opcodes in every method */
|
||||
|
||||
char* return_sig, /* Signature of this return_name method */
|
||||
/* (Must be "(II)V") */
|
||||
|
||||
char* obj_init_name, /* Method name in tclass to call first thing */
|
||||
/* when injecting java.lang.Object.<init> */
|
||||
|
||||
char* obj_init_sig, /* Signature of this obj_init_name method */
|
||||
/* (Must be "(Ljava/lang/Object;)V") */
|
||||
|
||||
char* newarray_name, /* Method name in tclass to call after every */
|
||||
/* newarray opcode in every method */
|
||||
|
||||
char* newarray_sig, /* Signature of this method */
|
||||
/* (Must be "(Ljava/lang/Object;II)V") */
|
||||
|
||||
unsigned char
|
||||
**pnew_file_image, /* Returns a pointer to new classfile image */
|
||||
|
||||
long *pnew_file_len, /* Returns the length of the new image */
|
||||
|
||||
FatalErrorHandler
|
||||
fatal_error_handler, /* Pointer to function to call on any */
|
||||
/* fatal error. NULL sends error to stderr */
|
||||
|
||||
MethodNumberRegister
|
||||
mnum_callback /* Pointer to function that gets called */
|
||||
/* with all details on methods in this */
|
||||
/* class. NULL means skip this call. */
|
||||
|
||||
);
|
||||
|
||||
|
||||
/* External to read the class name out of a class file .
|
||||
*
|
||||
* WARNING: If You change the typedef, you MUST change
|
||||
* multiple things in this file, including this name.
|
||||
*/
|
||||
|
||||
#define JAVA_CRW_DEMO_CLASSNAME_SYMBOLS \
|
||||
{ "java_crw_demo_classname", "_java_crw_demo_classname@12" }
|
||||
|
||||
/* Typedef needed for type casting in dynamic access situations. */
|
||||
|
||||
typedef char * (JNICALL *JavaCrwDemoClassname)(
|
||||
const unsigned char *file_image,
|
||||
long file_len,
|
||||
FatalErrorHandler fatal_error_handler);
|
||||
|
||||
JNIEXPORT char * JNICALL java_crw_demo_classname(
|
||||
const unsigned char *file_image,
|
||||
long file_len,
|
||||
FatalErrorHandler fatal_error_handler);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
@ -1,144 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Sample GNU Makefile for building
|
||||
#
|
||||
# Example uses:
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparc]
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparcv9]
|
||||
# gnumake JDK=<java_home> OSNAME=linux [OPT=true]
|
||||
# gnumake JDK=<java_home> OSNAME=win32 [OPT=true]
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Source lists
|
||||
LIBNAME=java_crw_demo
|
||||
SOURCES=java_crw_demo.c
|
||||
|
||||
# Solaris Studio C Compiler Version 12.4
|
||||
ifeq ($(OSNAME), solaris)
|
||||
# Sun Solaris Compiler options needed
|
||||
COMMON_FLAGS=-mt -KPIC
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -Xa -v -xc99=%none
|
||||
# Check LIBARCH for any special compiler options
|
||||
LIBARCH=$(shell uname -p)
|
||||
ifeq ($(LIBARCH), sparc)
|
||||
COMMON_FLAGS+=-xarch=v8 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(LIBARCH), sparcv9)
|
||||
COMMON_FLAGS+=-xarch=v9 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-xO2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-z defs -ztext
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -G -o $@
|
||||
endif
|
||||
|
||||
# Linux GNU C Compiler
|
||||
ifeq ($(OSNAME), linux)
|
||||
# GNU Compiler options needed to build it
|
||||
COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-O2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -shared -o $@
|
||||
endif
|
||||
|
||||
# Windows Microsoft C/C++ Optimizing Compiler Version 12
|
||||
ifeq ($(OSNAME), win32)
|
||||
CC=cl
|
||||
# Compiler options needed to build it
|
||||
COMMON_FLAGS=-Gy -DWIN32
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+=-W0 -WX
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS= -Ox -Op -Zi $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS= -Od -Zi $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.obj)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=$(LIBNAME).dll
|
||||
LDFLAGS=
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=
|
||||
# Building a shared library
|
||||
LINK_SHARED=link -dll -out:$@
|
||||
endif
|
||||
|
||||
# Common -I options
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME)
|
||||
|
||||
# Default rule (build both native library and jar file)
|
||||
all: $(LIBRARY)
|
||||
|
||||
# Build native library
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
|
||||
|
||||
# Cleanup the built bits
|
||||
clean:
|
||||
rm -f -r classes
|
||||
rm -f $(LIBRARY) $(OBJECTS)
|
||||
|
||||
# Compilation rule only needed on Windows
|
||||
ifeq ($(OSNAME), win32)
|
||||
%.obj: %.c
|
||||
$(COMPILE.c) $<
|
||||
endif
|
||||
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Java class to hold static methods which will be called in byte code
|
||||
* injections of all class files.
|
||||
*/
|
||||
|
||||
public class Minst {
|
||||
|
||||
/* Master switch that activates methods. */
|
||||
|
||||
private static int engaged = 0;
|
||||
|
||||
/* At the very beginning of every method, a call to method_entry()
|
||||
* is injected.
|
||||
*/
|
||||
|
||||
public static void method_entry(int cnum, int mnum) {
|
||||
Class<Minst> x = Minst.class;
|
||||
synchronized ( x ) {
|
||||
if ( engaged > 0 ) {
|
||||
engaged = 0;
|
||||
String className = "Unknown";
|
||||
String methodName = "Unknown";
|
||||
Exception exp = new Exception();
|
||||
StackTraceElement[] stack = exp.getStackTrace();
|
||||
if (stack.length > 1) {
|
||||
StackTraceElement location = stack[1];
|
||||
className = location.getClassName();
|
||||
methodName = location.getMethodName();
|
||||
}
|
||||
System.out.println("Reached method entry: " +
|
||||
className + "." + methodName + "()");
|
||||
engaged++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
minst
|
||||
|
||||
This agent library can be used to inject code at method calls.
|
||||
It uses the same java_crw_demo library used by HPROF to do BCI on all
|
||||
or selected classfiles loaded into the Virtual Machine.
|
||||
The class Minst.java can be customized to do whatever you wish,
|
||||
within reason of course, and does not call native methods directly.
|
||||
|
||||
You can use this agent library as follows:
|
||||
|
||||
java -agentlib:minst ...
|
||||
|
||||
To get help on the available options try:
|
||||
|
||||
java -agentlib:minst=help
|
||||
|
||||
See ${JAVA_HOME}/demo/jvmti/index.html for help running and building agents.
|
||||
|
@ -1,481 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdlib.h"
|
||||
|
||||
#include "minst.h"
|
||||
#include "java_crw_demo.h"
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* Some constant maximum sizes */
|
||||
|
||||
#define MAX_TOKEN_LENGTH 80
|
||||
#define MAX_METHOD_NAME_LENGTH 256
|
||||
|
||||
/* Some constant names that tie to Java class/method names.
|
||||
* We assume the Java class whose static methods we will be calling
|
||||
* looks like:
|
||||
*
|
||||
* public class Minst {
|
||||
* private static int engaged;
|
||||
* private static native void _method_entry(Object thr, int cnum, int mnum);
|
||||
* public static void method_entry(int cnum, int mnum)
|
||||
* {
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
#define MINST_class Minst /* Name of class we are using */
|
||||
#define MINST_entry method_entry /* Name of java entry method */
|
||||
#define MINST_engaged engaged /* Name of java static field */
|
||||
|
||||
/* C macros to create strings from tokens */
|
||||
#define _STRING(s) #s
|
||||
#define STRING(s) _STRING(s)
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/* Global agent data structure */
|
||||
|
||||
typedef struct {
|
||||
/* JVMTI Environment */
|
||||
jvmtiEnv *jvmti;
|
||||
jboolean vm_is_dead;
|
||||
jboolean vm_is_started;
|
||||
/* Data access Lock */
|
||||
jrawMonitorID lock;
|
||||
/* Options */
|
||||
char *include;
|
||||
char *exclude;
|
||||
/* Class Count/ID */
|
||||
jint ccount;
|
||||
} GlobalAgentData;
|
||||
|
||||
static GlobalAgentData *gdata;
|
||||
|
||||
/* Enter a critical section by doing a JVMTI Raw Monitor Enter */
|
||||
static void
|
||||
enter_critical_section(jvmtiEnv *jvmti)
|
||||
{
|
||||
jvmtiError error;
|
||||
|
||||
error = (*jvmti)->RawMonitorEnter(jvmti, gdata->lock);
|
||||
check_jvmti_error(jvmti, error, "Cannot enter with raw monitor");
|
||||
}
|
||||
|
||||
/* Exit a critical section by doing a JVMTI Raw Monitor Exit */
|
||||
static void
|
||||
exit_critical_section(jvmtiEnv *jvmti)
|
||||
{
|
||||
jvmtiError error;
|
||||
|
||||
error = (*jvmti)->RawMonitorExit(jvmti, gdata->lock);
|
||||
check_jvmti_error(jvmti, error, "Cannot exit with raw monitor");
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_START */
|
||||
static void JNICALL
|
||||
cbVMStart(jvmtiEnv *jvmti, JNIEnv *env)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
/* Indicate VM has started */
|
||||
gdata->vm_is_started = JNI_TRUE;
|
||||
} exit_critical_section(jvmti);
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_INIT */
|
||||
static void JNICALL
|
||||
cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
jclass klass;
|
||||
jfieldID field;
|
||||
|
||||
/* Register Natives for class whose methods we use */
|
||||
klass = (*env)->FindClass(env, STRING(MINST_class));
|
||||
if ( klass == NULL ) {
|
||||
fatal_error("ERROR: JNI: Cannot find %s with FindClass\n",
|
||||
STRING(MINST_class));
|
||||
}
|
||||
|
||||
/* Engage calls. */
|
||||
field = (*env)->GetStaticFieldID(env, klass, STRING(MINST_engaged), "I");
|
||||
if ( field == NULL ) {
|
||||
fatal_error("ERROR: JNI: Cannot get field from %s\n",
|
||||
STRING(MINST_class));
|
||||
}
|
||||
(*env)->SetStaticIntField(env, klass, field, 1);
|
||||
} exit_critical_section(jvmti);
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_DEATH */
|
||||
static void JNICALL
|
||||
cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
jclass klass;
|
||||
jfieldID field;
|
||||
|
||||
/* The VM has died. */
|
||||
stdout_message("VMDeath\n");
|
||||
|
||||
/* Disengage calls in MINST_class. */
|
||||
klass = (*env)->FindClass(env, STRING(MINST_class));
|
||||
if ( klass == NULL ) {
|
||||
fatal_error("ERROR: JNI: Cannot find %s with FindClass\n",
|
||||
STRING(MINST_class));
|
||||
}
|
||||
field = (*env)->GetStaticFieldID(env, klass, STRING(MINST_engaged), "I");
|
||||
if ( field == NULL ) {
|
||||
fatal_error("ERROR: JNI: Cannot get field from %s\n",
|
||||
STRING(MINST_class));
|
||||
}
|
||||
(*env)->SetStaticIntField(env, klass, field, -1);
|
||||
|
||||
/* The critical section here is important to hold back the VM death
|
||||
* until all other callbacks have completed.
|
||||
*/
|
||||
|
||||
/* Since this critical section could be holding up other threads
|
||||
* in other event callbacks, we need to indicate that the VM is
|
||||
* dead so that the other callbacks can short circuit their work.
|
||||
* We don't expect any further events after VmDeath but we do need
|
||||
* to be careful that existing threads might be in our own agent
|
||||
* callback code.
|
||||
*/
|
||||
gdata->vm_is_dead = JNI_TRUE;
|
||||
|
||||
} exit_critical_section(jvmti);
|
||||
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */
|
||||
static void JNICALL
|
||||
cbClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv* env,
|
||||
jclass class_being_redefined, jobject loader,
|
||||
const char* name, jobject protection_domain,
|
||||
jint class_data_len, const unsigned char* class_data,
|
||||
jint* new_class_data_len, unsigned char** new_class_data)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
/* It's possible we get here right after VmDeath event, be careful */
|
||||
if ( !gdata->vm_is_dead ) {
|
||||
|
||||
const char *classname;
|
||||
|
||||
/* Name could be NULL */
|
||||
if ( name == NULL ) {
|
||||
classname = java_crw_demo_classname(class_data, class_data_len,
|
||||
NULL);
|
||||
if ( classname == NULL ) {
|
||||
fatal_error("ERROR: No classname inside classfile\n");
|
||||
}
|
||||
} else {
|
||||
classname = strdup(name);
|
||||
if ( classname == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
}
|
||||
|
||||
*new_class_data_len = 0;
|
||||
*new_class_data = NULL;
|
||||
|
||||
/* The tracker class itself? */
|
||||
if ( interested((char*)classname, "", gdata->include, gdata->exclude)
|
||||
&& strcmp(classname, STRING(MINST_class)) != 0 ) {
|
||||
jint cnum;
|
||||
int system_class;
|
||||
unsigned char *new_image;
|
||||
long new_length;
|
||||
|
||||
/* Get unique number for every class file image loaded */
|
||||
cnum = gdata->ccount++;
|
||||
|
||||
/* Is it a system class? If the class load is before VmStart
|
||||
* then we will consider it a system class that should
|
||||
* be treated carefully. (See java_crw_demo)
|
||||
*/
|
||||
system_class = 0;
|
||||
if ( !gdata->vm_is_started ) {
|
||||
system_class = 1;
|
||||
}
|
||||
|
||||
new_image = NULL;
|
||||
new_length = 0;
|
||||
|
||||
/* Call the class file reader/write demo code */
|
||||
java_crw_demo(cnum,
|
||||
classname,
|
||||
class_data,
|
||||
class_data_len,
|
||||
system_class,
|
||||
STRING(MINST_class), "L" STRING(MINST_class) ";",
|
||||
STRING(MINST_entry), "(II)V",
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
&new_image,
|
||||
&new_length,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* If we got back a new class image, return it back as "the"
|
||||
* new class image. This must be JVMTI Allocate space.
|
||||
*/
|
||||
if ( new_length > 0 ) {
|
||||
unsigned char *jvmti_space;
|
||||
|
||||
jvmti_space = (unsigned char *)allocate(jvmti, (jint)new_length);
|
||||
(void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length);
|
||||
*new_class_data_len = (jint)new_length;
|
||||
*new_class_data = jvmti_space; /* VM will deallocate */
|
||||
}
|
||||
|
||||
/* Always free up the space we get from java_crw_demo() */
|
||||
if ( new_image != NULL ) {
|
||||
(void)free((void*)new_image); /* Free malloc() space with free() */
|
||||
}
|
||||
}
|
||||
(void)free((void*)classname);
|
||||
}
|
||||
} exit_critical_section(jvmti);
|
||||
}
|
||||
|
||||
/* Parse the options for this minst agent */
|
||||
static void
|
||||
parse_agent_options(char *options)
|
||||
{
|
||||
char token[MAX_TOKEN_LENGTH];
|
||||
char *next;
|
||||
|
||||
/* Parse options and set flags in gdata */
|
||||
if ( options==NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the first token from the options string. */
|
||||
next = get_token(options, ",=", token, sizeof(token));
|
||||
|
||||
/* While not at the end of the options string, process this option. */
|
||||
while ( next != NULL ) {
|
||||
if ( strcmp(token,"help")==0 ) {
|
||||
stdout_message("The minst JVMTI demo agent\n");
|
||||
stdout_message("\n");
|
||||
stdout_message(" java -agent:minst[=options] ...\n");
|
||||
stdout_message("\n");
|
||||
stdout_message("The options are comma separated:\n");
|
||||
stdout_message("\t help\t\t\t Print help information\n");
|
||||
stdout_message("\t include=item\t\t Only these classes/methods\n");
|
||||
stdout_message("\t exclude=item\t\t Exclude these classes/methods\n");
|
||||
stdout_message("\n");
|
||||
stdout_message("item\t Qualified class and/or method names\n");
|
||||
stdout_message("\t\t e.g. (*.<init>;Foobar.method;sun.*)\n");
|
||||
stdout_message("\n");
|
||||
exit(0);
|
||||
} else if ( strcmp(token,"include")==0 ) {
|
||||
int used;
|
||||
int maxlen;
|
||||
|
||||
maxlen = MAX_METHOD_NAME_LENGTH;
|
||||
if ( gdata->include == NULL ) {
|
||||
gdata->include = (char*)calloc(maxlen+1, 1);
|
||||
used = 0;
|
||||
} else {
|
||||
used = (int)strlen(gdata->include);
|
||||
gdata->include[used++] = ',';
|
||||
gdata->include[used] = 0;
|
||||
gdata->include = (char*)
|
||||
realloc((void*)gdata->include, used+maxlen+1);
|
||||
}
|
||||
if ( gdata->include == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
/* Add this item to the list */
|
||||
next = get_token(next, ",=", gdata->include+used, maxlen);
|
||||
/* Check for token scan error */
|
||||
if ( next==NULL ) {
|
||||
fatal_error("ERROR: include option error\n");
|
||||
}
|
||||
} else if ( strcmp(token,"exclude")==0 ) {
|
||||
int used;
|
||||
int maxlen;
|
||||
|
||||
maxlen = MAX_METHOD_NAME_LENGTH;
|
||||
if ( gdata->exclude == NULL ) {
|
||||
gdata->exclude = (char*)calloc(maxlen+1, 1);
|
||||
used = 0;
|
||||
} else {
|
||||
used = (int)strlen(gdata->exclude);
|
||||
gdata->exclude[used++] = ',';
|
||||
gdata->exclude[used] = 0;
|
||||
gdata->exclude = (char*)
|
||||
realloc((void*)gdata->exclude, used+maxlen+1);
|
||||
}
|
||||
if ( gdata->exclude == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
/* Add this item to the list */
|
||||
next = get_token(next, ",=", gdata->exclude+used, maxlen);
|
||||
/* Check for token scan error */
|
||||
if ( next==NULL ) {
|
||||
fatal_error("ERROR: exclude option error\n");
|
||||
}
|
||||
} else if ( token[0]!=0 ) {
|
||||
/* We got a non-empty token and we don't know what it is. */
|
||||
fatal_error("ERROR: Unknown option: %s\n", token);
|
||||
}
|
||||
/* Get the next token (returns NULL if there are no more) */
|
||||
next = get_token(next, ",=", token, sizeof(token));
|
||||
}
|
||||
}
|
||||
|
||||
/* Agent_OnLoad: This is called immediately after the shared library is
|
||||
* loaded. This is the first code executed.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
static GlobalAgentData data;
|
||||
jvmtiEnv *jvmti;
|
||||
jvmtiError error;
|
||||
jint res;
|
||||
jvmtiCapabilities capabilities;
|
||||
jvmtiEventCallbacks callbacks;
|
||||
|
||||
/* Setup initial global agent data area
|
||||
* Use of static/extern data should be handled carefully here.
|
||||
* We need to make sure that we are able to cleanup after ourselves
|
||||
* so anything allocated in this library needs to be freed in
|
||||
* the Agent_OnUnload() function.
|
||||
*/
|
||||
(void)memset((void*)&data, 0, sizeof(data));
|
||||
gdata = &data;
|
||||
|
||||
/* First thing we need to do is get the jvmtiEnv* or JVMTI environment */
|
||||
res = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1);
|
||||
if (res != JNI_OK) {
|
||||
/* This means that the VM was unable to obtain this version of the
|
||||
* JVMTI interface, this is a fatal error.
|
||||
*/
|
||||
fatal_error("ERROR: Unable to access JVMTI Version 1 (0x%x),"
|
||||
" is your JDK a 5.0 or newer version?"
|
||||
" JNIEnv's GetEnv() returned %d\n",
|
||||
JVMTI_VERSION_1, res);
|
||||
}
|
||||
|
||||
/* Here we save the jvmtiEnv* for Agent_OnUnload(). */
|
||||
gdata->jvmti = jvmti;
|
||||
|
||||
/* Parse any options supplied on java command line */
|
||||
parse_agent_options(options);
|
||||
|
||||
/* Immediately after getting the jvmtiEnv* we need to ask for the
|
||||
* capabilities this agent will need. In this case we need to make
|
||||
* sure that we can get all class load hooks.
|
||||
*/
|
||||
(void)memset(&capabilities,0, sizeof(capabilities));
|
||||
capabilities.can_generate_all_class_hook_events = 1;
|
||||
error = (*jvmti)->AddCapabilities(jvmti, &capabilities);
|
||||
check_jvmti_error(jvmti, error, "Unable to get necessary JVMTI capabilities.");
|
||||
|
||||
/* Next we need to provide the pointers to the callback functions to
|
||||
* to this jvmtiEnv*
|
||||
*/
|
||||
(void)memset(&callbacks,0, sizeof(callbacks));
|
||||
/* JVMTI_EVENT_VM_START */
|
||||
callbacks.VMStart = &cbVMStart;
|
||||
/* JVMTI_EVENT_VM_INIT */
|
||||
callbacks.VMInit = &cbVMInit;
|
||||
/* JVMTI_EVENT_VM_DEATH */
|
||||
callbacks.VMDeath = &cbVMDeath;
|
||||
/* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */
|
||||
callbacks.ClassFileLoadHook = &cbClassFileLoadHook;
|
||||
error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks));
|
||||
check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks");
|
||||
|
||||
/* At first the only initial events we are interested in are VM
|
||||
* initialization, VM death, and Class File Loads.
|
||||
* Once the VM is initialized we will request more events.
|
||||
*/
|
||||
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_START, (jthread)NULL);
|
||||
check_jvmti_error(jvmti, error, "Cannot set event notification");
|
||||
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_INIT, (jthread)NULL);
|
||||
check_jvmti_error(jvmti, error, "Cannot set event notification");
|
||||
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_DEATH, (jthread)NULL);
|
||||
check_jvmti_error(jvmti, error, "Cannot set event notification");
|
||||
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread)NULL);
|
||||
check_jvmti_error(jvmti, error, "Cannot set event notification");
|
||||
|
||||
/* Here we create a raw monitor for our use in this agent to
|
||||
* protect critical sections of code.
|
||||
*/
|
||||
error = (*jvmti)->CreateRawMonitor(jvmti, "agent data", &(gdata->lock));
|
||||
check_jvmti_error(jvmti, error, "Cannot create raw monitor");
|
||||
|
||||
/* Add demo jar file to boot classpath */
|
||||
add_demo_jar_to_bootclasspath(jvmti, "minst");
|
||||
|
||||
/* We return JNI_OK to signify success */
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
/* Agent_OnUnload: This is called immediately before the shared library is
|
||||
* unloaded. This is the last code executed.
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
/* Make sure all malloc/calloc/strdup space is freed */
|
||||
if ( gdata->include != NULL ) {
|
||||
(void)free((void*)gdata->include);
|
||||
gdata->include = NULL;
|
||||
}
|
||||
if ( gdata->exclude != NULL ) {
|
||||
(void)free((void*)gdata->exclude);
|
||||
gdata->exclude = NULL;
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/* Primary minst #include file, should be included by most if not
|
||||
* all minst source files. Gives access to the global data structure
|
||||
* and all global macros.
|
||||
*/
|
||||
|
||||
#ifndef MINST_H
|
||||
#define MINST_H
|
||||
|
||||
/* Standard C functions used throughout. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* General JVM/Java functions, types and macros. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
/* Utility functions */
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
#endif
|
@ -1,163 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Sample GNU Makefile for building JVMTI Demo minst
|
||||
#
|
||||
# Example uses:
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparc]
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparcv9]
|
||||
# gnumake JDK=<java_home> OSNAME=linux [OPT=true]
|
||||
# gnumake JDK=<java_home> OSNAME=win32 [OPT=true]
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Source lists
|
||||
LIBNAME=minst
|
||||
SOURCES=minst.c ../agent_util/agent_util.c
|
||||
JAVA_SOURCES=Minst.java
|
||||
|
||||
# Name of jar file that needs to be created
|
||||
JARFILE=minst.jar
|
||||
|
||||
# Solaris Studio C Compiler Version 12.4
|
||||
ifeq ($(OSNAME), solaris)
|
||||
# Sun Solaris Compiler options needed
|
||||
COMMON_FLAGS=-mt -KPIC
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -Xa -v -xc99=%none
|
||||
# Check LIBARCH for any special compiler options
|
||||
LIBARCH=$(shell uname -p)
|
||||
ifeq ($(LIBARCH), sparc)
|
||||
COMMON_FLAGS+=-xarch=v8 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(LIBARCH), sparcv9)
|
||||
COMMON_FLAGS+=-xarch=v9 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-xO2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-z defs -ztext
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-L $(JDK)/jre/lib/$(LIBARCH) -ljava_crw_demo -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -G -o $@
|
||||
endif
|
||||
|
||||
# Linux GNU C Compiler
|
||||
ifeq ($(OSNAME), linux)
|
||||
# GNU Compiler options needed to build it
|
||||
COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-O2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-L $(JDK)/jre/lib/$(LIBARCH) -ljava_crw_demo -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -shared -o $@
|
||||
endif
|
||||
|
||||
# Windows Microsoft C/C++ Optimizing Compiler Version 12
|
||||
ifeq ($(OSNAME), win32)
|
||||
CC=cl
|
||||
# Compiler options needed to build it
|
||||
COMMON_FLAGS=-Gy -DWIN32
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+=-W0 -WX
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS= -Ox -Op -Zi $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS= -Od -Zi $(COMMON_FLAGS)
|
||||
endif
|
||||
# Add in java_crw_demo obj file on windows (easier)
|
||||
SOURCES+=../java_crw_demo/java_crw_demo.c
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.obj)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=$(LIBNAME).dll
|
||||
LDFLAGS=
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=$(JDK)/
|
||||
# Building a shared library
|
||||
LINK_SHARED=link -dll -out:$@
|
||||
endif
|
||||
|
||||
# Common -I options
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../agent_util
|
||||
CFLAGS += -I../java_crw_demo
|
||||
CFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME)
|
||||
|
||||
# Default rule (build both native library and jar file)
|
||||
all: $(LIBRARY) $(JARFILE)
|
||||
|
||||
# Build native library
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
|
||||
|
||||
# Build jar file
|
||||
$(JARFILE): $(JAVA_SOURCES)
|
||||
rm -f -r classes
|
||||
mkdir -p classes
|
||||
$(JDK)/bin/javac -d classes $(JAVA_SOURCES)
|
||||
(cd classes; $(JDK)/bin/jar cf ../$@ *)
|
||||
|
||||
# Cleanup the built bits
|
||||
clean:
|
||||
rm -f -r classes
|
||||
rm -f $(LIBRARY) $(JARFILE) $(OBJECTS)
|
||||
|
||||
# Simple tester
|
||||
test: all
|
||||
LD_LIBRARY_PATH=. $(JDK)/bin/java -agentlib:$(LIBNAME) -Xbootclasspath/a:./$(JARFILE) -version
|
||||
|
||||
# Compilation rule only needed on Windows
|
||||
ifeq ($(OSNAME), win32)
|
||||
%.obj: %.c
|
||||
$(COMPILE.c) $<
|
||||
endif
|
||||
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Java class to hold static methods which will be called in byte code
|
||||
* injections of all class files.
|
||||
*/
|
||||
|
||||
public class Mtrace {
|
||||
|
||||
/* Master switch that activates methods. */
|
||||
|
||||
private static int engaged = 0;
|
||||
|
||||
/* At the very beginning of every method, a call to method_entry()
|
||||
* is injected.
|
||||
*/
|
||||
|
||||
private static native void _method_entry(Object thr, int cnum, int mnum);
|
||||
public static void method_entry(int cnum, int mnum)
|
||||
{
|
||||
if ( engaged != 0 ) {
|
||||
_method_entry(Thread.currentThread(), cnum, mnum);
|
||||
}
|
||||
}
|
||||
|
||||
/* Before any of the return bytecodes, a call to method_exit()
|
||||
* is injected.
|
||||
*/
|
||||
|
||||
private static native void _method_exit(Object thr, int cnum, int mnum);
|
||||
public static void method_exit(int cnum, int mnum)
|
||||
{
|
||||
if ( engaged != 0 ) {
|
||||
_method_exit(Thread.currentThread(), cnum, mnum);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
mtrace
|
||||
|
||||
This agent library can be used to track method call and return counts.
|
||||
It uses the same java_crw_demo library used by HPROF to do BCI on all or
|
||||
selected classfiles loaded into the Virtual Machine. It will print out a
|
||||
sorted list of the most heavily used classes (as determined by the number
|
||||
of method calls into the class) and also include the call and return counts
|
||||
for all methods that are called.
|
||||
|
||||
You can use this agent library as follows:
|
||||
|
||||
java -Xbootclasspath/a:mtrace.jar -agentlib:mtrace ...
|
||||
|
||||
To get help on the available options try:
|
||||
|
||||
java -agentlib:mtrace=help
|
||||
|
||||
See ${JAVA_HOME}/demo/jvmti/index.html for help running and building agents.
|
||||
|
@ -1,833 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdlib.h"
|
||||
|
||||
#include "mtrace.h"
|
||||
#include "java_crw_demo.h"
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* Some constant maximum sizes */
|
||||
|
||||
#define MAX_TOKEN_LENGTH 16
|
||||
#define MAX_THREAD_NAME_LENGTH 512
|
||||
#define MAX_METHOD_NAME_LENGTH 1024
|
||||
|
||||
/* Some constant names that tie to Java class/method names.
|
||||
* We assume the Java class whose static methods we will be calling
|
||||
* looks like:
|
||||
*
|
||||
* public class Mtrace {
|
||||
* private static int engaged;
|
||||
* private static native void _method_entry(Object thr, int cnum, int mnum);
|
||||
* public static void method_entry(int cnum, int mnum)
|
||||
* {
|
||||
* if ( engaged != 0 ) {
|
||||
* _method_entry(Thread.currentThread(), cnum, mnum);
|
||||
* }
|
||||
* }
|
||||
* private static native void _method_exit(Object thr, int cnum, int mnum);
|
||||
* public static void method_exit(int cnum, int mnum)
|
||||
* {
|
||||
* if ( engaged != 0 ) {
|
||||
* _method_exit(Thread.currentThread(), cnum, mnum);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* The engaged field allows us to inject all classes (even system classes)
|
||||
* and delay the actual calls to the native code until the VM has reached
|
||||
* a safe time to call native methods (Past the JVMTI VM_START event).
|
||||
*
|
||||
*/
|
||||
|
||||
#define MTRACE_class Mtrace /* Name of class we are using */
|
||||
#define MTRACE_entry method_entry /* Name of java entry method */
|
||||
#define MTRACE_exit method_exit /* Name of java exit method */
|
||||
#define MTRACE_native_entry _method_entry /* Name of java entry native */
|
||||
#define MTRACE_native_exit _method_exit /* Name of java exit native */
|
||||
#define MTRACE_engaged engaged /* Name of java static field */
|
||||
|
||||
/* C macros to create strings from tokens */
|
||||
#define _STRING(s) #s
|
||||
#define STRING(s) _STRING(s)
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/* Data structure to hold method and class information in agent */
|
||||
|
||||
typedef struct MethodInfo {
|
||||
const char *name; /* Method name */
|
||||
const char *signature; /* Method signature */
|
||||
int calls; /* Method call count */
|
||||
int returns; /* Method return count */
|
||||
} MethodInfo;
|
||||
|
||||
typedef struct ClassInfo {
|
||||
const char *name; /* Class name */
|
||||
int mcount; /* Method count */
|
||||
MethodInfo *methods; /* Method information */
|
||||
int calls; /* Method call count for this class */
|
||||
} ClassInfo;
|
||||
|
||||
/* Global agent data structure */
|
||||
|
||||
typedef struct {
|
||||
/* JVMTI Environment */
|
||||
jvmtiEnv *jvmti;
|
||||
jboolean vm_is_dead;
|
||||
jboolean vm_is_started;
|
||||
/* Data access Lock */
|
||||
jrawMonitorID lock;
|
||||
/* Options */
|
||||
char *include;
|
||||
char *exclude;
|
||||
int max_count;
|
||||
/* ClassInfo Table */
|
||||
ClassInfo *classes;
|
||||
jint ccount;
|
||||
} GlobalAgentData;
|
||||
|
||||
static GlobalAgentData *gdata;
|
||||
|
||||
/* Enter a critical section by doing a JVMTI Raw Monitor Enter */
|
||||
static void
|
||||
enter_critical_section(jvmtiEnv *jvmti)
|
||||
{
|
||||
jvmtiError error;
|
||||
|
||||
error = (*jvmti)->RawMonitorEnter(jvmti, gdata->lock);
|
||||
check_jvmti_error(jvmti, error, "Cannot enter with raw monitor");
|
||||
}
|
||||
|
||||
/* Exit a critical section by doing a JVMTI Raw Monitor Exit */
|
||||
static void
|
||||
exit_critical_section(jvmtiEnv *jvmti)
|
||||
{
|
||||
jvmtiError error;
|
||||
|
||||
error = (*jvmti)->RawMonitorExit(jvmti, gdata->lock);
|
||||
check_jvmti_error(jvmti, error, "Cannot exit with raw monitor");
|
||||
}
|
||||
|
||||
/* Get a name for a jthread */
|
||||
static void
|
||||
get_thread_name(jvmtiEnv *jvmti, jthread thread, char *tname, int maxlen)
|
||||
{
|
||||
jvmtiThreadInfo info;
|
||||
jvmtiError error;
|
||||
|
||||
/* Make sure the stack variables are garbage free */
|
||||
(void)memset(&info,0, sizeof(info));
|
||||
|
||||
/* Assume the name is unknown for now */
|
||||
(void)strcpy(tname, "Unknown");
|
||||
|
||||
/* Get the thread information, which includes the name */
|
||||
error = (*jvmti)->GetThreadInfo(jvmti, thread, &info);
|
||||
check_jvmti_error(jvmti, error, "Cannot get thread info");
|
||||
|
||||
/* The thread might not have a name, be careful here. */
|
||||
if ( info.name != NULL ) {
|
||||
int len;
|
||||
|
||||
/* Copy the thread name into tname if it will fit */
|
||||
len = (int)strlen(info.name);
|
||||
if ( len < maxlen ) {
|
||||
(void)strcpy(tname, info.name);
|
||||
}
|
||||
|
||||
/* Every string allocated by JVMTI needs to be freed */
|
||||
deallocate(jvmti, (void*)info.name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Qsort class compare routine */
|
||||
static int
|
||||
class_compar(const void *e1, const void *e2)
|
||||
{
|
||||
ClassInfo *c1 = (ClassInfo*)e1;
|
||||
ClassInfo *c2 = (ClassInfo*)e2;
|
||||
if ( c1->calls > c2->calls ) return 1;
|
||||
if ( c1->calls < c2->calls ) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Qsort method compare routine */
|
||||
static int
|
||||
method_compar(const void *e1, const void *e2)
|
||||
{
|
||||
MethodInfo *m1 = (MethodInfo*)e1;
|
||||
MethodInfo *m2 = (MethodInfo*)e2;
|
||||
if ( m1->calls > m2->calls ) return 1;
|
||||
if ( m1->calls < m2->calls ) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Callback from java_crw_demo() that gives us mnum mappings */
|
||||
static void
|
||||
mnum_callbacks(unsigned cnum, const char **names, const char**sigs, int mcount)
|
||||
{
|
||||
ClassInfo *cp;
|
||||
int mnum;
|
||||
|
||||
if ( cnum >= (unsigned)gdata->ccount ) {
|
||||
fatal_error("ERROR: Class number out of range\n");
|
||||
}
|
||||
if ( mcount == 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
cp = gdata->classes + (int)cnum;
|
||||
cp->calls = 0;
|
||||
cp->mcount = mcount;
|
||||
cp->methods = (MethodInfo*)calloc(mcount, sizeof(MethodInfo));
|
||||
if ( cp->methods == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
|
||||
for ( mnum = 0 ; mnum < mcount ; mnum++ ) {
|
||||
MethodInfo *mp;
|
||||
|
||||
mp = cp->methods + mnum;
|
||||
mp->name = (const char *)strdup(names[mnum]);
|
||||
if ( mp->name == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
mp->signature = (const char *)strdup(sigs[mnum]);
|
||||
if ( mp->signature == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Java Native Method for entry */
|
||||
static void
|
||||
MTRACE_native_entry(JNIEnv *env, jclass klass, jobject thread, jint cnum, jint mnum)
|
||||
{
|
||||
enter_critical_section(gdata->jvmti); {
|
||||
/* It's possible we get here right after VmDeath event, be careful */
|
||||
if ( !gdata->vm_is_dead ) {
|
||||
ClassInfo *cp;
|
||||
MethodInfo *mp;
|
||||
|
||||
if ( cnum >= gdata->ccount ) {
|
||||
fatal_error("ERROR: Class number out of range\n");
|
||||
}
|
||||
cp = gdata->classes + cnum;
|
||||
if ( mnum >= cp->mcount ) {
|
||||
fatal_error("ERROR: Method number out of range\n");
|
||||
}
|
||||
mp = cp->methods + mnum;
|
||||
if ( interested((char*)cp->name, (char*)mp->name,
|
||||
gdata->include, gdata->exclude) ) {
|
||||
mp->calls++;
|
||||
cp->calls++;
|
||||
}
|
||||
}
|
||||
} exit_critical_section(gdata->jvmti);
|
||||
}
|
||||
|
||||
/* Java Native Method for exit */
|
||||
static void
|
||||
MTRACE_native_exit(JNIEnv *env, jclass klass, jobject thread, jint cnum, jint mnum)
|
||||
{
|
||||
enter_critical_section(gdata->jvmti); {
|
||||
/* It's possible we get here right after VmDeath event, be careful */
|
||||
if ( !gdata->vm_is_dead ) {
|
||||
ClassInfo *cp;
|
||||
MethodInfo *mp;
|
||||
|
||||
if ( cnum >= gdata->ccount ) {
|
||||
fatal_error("ERROR: Class number out of range\n");
|
||||
}
|
||||
cp = gdata->classes + cnum;
|
||||
if ( mnum >= cp->mcount ) {
|
||||
fatal_error("ERROR: Method number out of range\n");
|
||||
}
|
||||
mp = cp->methods + mnum;
|
||||
if ( interested((char*)cp->name, (char*)mp->name,
|
||||
gdata->include, gdata->exclude) ) {
|
||||
mp->returns++;
|
||||
}
|
||||
}
|
||||
} exit_critical_section(gdata->jvmti);
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_START */
|
||||
static void JNICALL
|
||||
cbVMStart(jvmtiEnv *jvmti, JNIEnv *env)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
jclass klass;
|
||||
jfieldID field;
|
||||
int rc;
|
||||
|
||||
/* Java Native Methods for class */
|
||||
static JNINativeMethod registry[2] = {
|
||||
{STRING(MTRACE_native_entry), "(Ljava/lang/Object;II)V",
|
||||
(void*)&MTRACE_native_entry},
|
||||
{STRING(MTRACE_native_exit), "(Ljava/lang/Object;II)V",
|
||||
(void*)&MTRACE_native_exit}
|
||||
};
|
||||
|
||||
/* The VM has started. */
|
||||
stdout_message("VMStart\n");
|
||||
|
||||
/* Register Natives for class whose methods we use */
|
||||
klass = (*env)->FindClass(env, STRING(MTRACE_class));
|
||||
if ( klass == NULL ) {
|
||||
fatal_error("ERROR: JNI: Cannot find %s with FindClass\n",
|
||||
STRING(MTRACE_class));
|
||||
}
|
||||
rc = (*env)->RegisterNatives(env, klass, registry, 2);
|
||||
if ( rc != 0 ) {
|
||||
fatal_error("ERROR: JNI: Cannot register native methods for %s\n",
|
||||
STRING(MTRACE_class));
|
||||
}
|
||||
|
||||
/* Engage calls. */
|
||||
field = (*env)->GetStaticFieldID(env, klass, STRING(MTRACE_engaged), "I");
|
||||
if ( field == NULL ) {
|
||||
fatal_error("ERROR: JNI: Cannot get field from %s\n",
|
||||
STRING(MTRACE_class));
|
||||
}
|
||||
(*env)->SetStaticIntField(env, klass, field, 1);
|
||||
|
||||
/* Indicate VM has started */
|
||||
gdata->vm_is_started = JNI_TRUE;
|
||||
|
||||
} exit_critical_section(jvmti);
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_INIT */
|
||||
static void JNICALL
|
||||
cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
char tname[MAX_THREAD_NAME_LENGTH];
|
||||
static jvmtiEvent events[] =
|
||||
{ JVMTI_EVENT_THREAD_START, JVMTI_EVENT_THREAD_END };
|
||||
int i;
|
||||
|
||||
/* The VM has started. */
|
||||
get_thread_name(jvmti, thread, tname, sizeof(tname));
|
||||
stdout_message("VMInit %s\n", tname);
|
||||
|
||||
/* The VM is now initialized, at this time we make our requests
|
||||
* for additional events.
|
||||
*/
|
||||
|
||||
for( i=0; i < (int)(sizeof(events)/sizeof(jvmtiEvent)); i++) {
|
||||
jvmtiError error;
|
||||
|
||||
/* Setup event notification modes */
|
||||
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
events[i], (jthread)NULL);
|
||||
check_jvmti_error(jvmti, error, "Cannot set event notification");
|
||||
}
|
||||
|
||||
} exit_critical_section(jvmti);
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_DEATH */
|
||||
static void JNICALL
|
||||
cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
jclass klass;
|
||||
jfieldID field;
|
||||
|
||||
/* The VM has died. */
|
||||
stdout_message("VMDeath\n");
|
||||
|
||||
/* Disengage calls in MTRACE_class. */
|
||||
klass = (*env)->FindClass(env, STRING(MTRACE_class));
|
||||
if ( klass == NULL ) {
|
||||
fatal_error("ERROR: JNI: Cannot find %s with FindClass\n",
|
||||
STRING(MTRACE_class));
|
||||
}
|
||||
field = (*env)->GetStaticFieldID(env, klass, STRING(MTRACE_engaged), "I");
|
||||
if ( field == NULL ) {
|
||||
fatal_error("ERROR: JNI: Cannot get field from %s\n",
|
||||
STRING(MTRACE_class));
|
||||
}
|
||||
(*env)->SetStaticIntField(env, klass, field, 0);
|
||||
|
||||
/* The critical section here is important to hold back the VM death
|
||||
* until all other callbacks have completed.
|
||||
*/
|
||||
|
||||
/* Since this critical section could be holding up other threads
|
||||
* in other event callbacks, we need to indicate that the VM is
|
||||
* dead so that the other callbacks can short circuit their work.
|
||||
* We don't expect any further events after VmDeath but we do need
|
||||
* to be careful that existing threads might be in our own agent
|
||||
* callback code.
|
||||
*/
|
||||
gdata->vm_is_dead = JNI_TRUE;
|
||||
|
||||
/* Dump out stats */
|
||||
stdout_message("Begin Class Stats\n");
|
||||
if ( gdata->ccount > 0 ) {
|
||||
int cnum;
|
||||
|
||||
/* Sort table (in place) by number of method calls into class. */
|
||||
/* Note: Do not use this table after this qsort! */
|
||||
qsort(gdata->classes, gdata->ccount, sizeof(ClassInfo),
|
||||
&class_compar);
|
||||
|
||||
/* Dump out gdata->max_count most called classes */
|
||||
for ( cnum=gdata->ccount-1 ;
|
||||
cnum >= 0 && cnum >= gdata->ccount - gdata->max_count;
|
||||
cnum-- ) {
|
||||
ClassInfo *cp;
|
||||
int mnum;
|
||||
|
||||
cp = gdata->classes + cnum;
|
||||
stdout_message("Class %s %d calls\n", cp->name, cp->calls);
|
||||
if ( cp->calls==0 ) continue;
|
||||
|
||||
/* Sort method table (in place) by number of method calls. */
|
||||
/* Note: Do not use this table after this qsort! */
|
||||
qsort(cp->methods, cp->mcount, sizeof(MethodInfo),
|
||||
&method_compar);
|
||||
for ( mnum=cp->mcount-1 ; mnum >= 0 ; mnum-- ) {
|
||||
MethodInfo *mp;
|
||||
|
||||
mp = cp->methods + mnum;
|
||||
if ( mp->calls==0 ) continue;
|
||||
stdout_message("\tMethod %s %s %d calls %d returns\n",
|
||||
mp->name, mp->signature, mp->calls, mp->returns);
|
||||
}
|
||||
}
|
||||
}
|
||||
stdout_message("End Class Stats\n");
|
||||
(void)fflush(stdout);
|
||||
|
||||
} exit_critical_section(jvmti);
|
||||
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_THREAD_START */
|
||||
static void JNICALL
|
||||
cbThreadStart(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
/* It's possible we get here right after VmDeath event, be careful */
|
||||
if ( !gdata->vm_is_dead ) {
|
||||
char tname[MAX_THREAD_NAME_LENGTH];
|
||||
|
||||
get_thread_name(jvmti, thread, tname, sizeof(tname));
|
||||
stdout_message("ThreadStart %s\n", tname);
|
||||
}
|
||||
} exit_critical_section(jvmti);
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_THREAD_END */
|
||||
static void JNICALL
|
||||
cbThreadEnd(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
/* It's possible we get here right after VmDeath event, be careful */
|
||||
if ( !gdata->vm_is_dead ) {
|
||||
char tname[MAX_THREAD_NAME_LENGTH];
|
||||
|
||||
get_thread_name(jvmti, thread, tname, sizeof(tname));
|
||||
stdout_message("ThreadEnd %s\n", tname);
|
||||
}
|
||||
} exit_critical_section(jvmti);
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */
|
||||
static void JNICALL
|
||||
cbClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv* env,
|
||||
jclass class_being_redefined, jobject loader,
|
||||
const char* name, jobject protection_domain,
|
||||
jint class_data_len, const unsigned char* class_data,
|
||||
jint* new_class_data_len, unsigned char** new_class_data)
|
||||
{
|
||||
enter_critical_section(jvmti); {
|
||||
/* It's possible we get here right after VmDeath event, be careful */
|
||||
if ( !gdata->vm_is_dead ) {
|
||||
|
||||
const char *classname;
|
||||
|
||||
/* Name could be NULL */
|
||||
if ( name == NULL ) {
|
||||
classname = java_crw_demo_classname(class_data, class_data_len,
|
||||
NULL);
|
||||
if ( classname == NULL ) {
|
||||
fatal_error("ERROR: No classname inside classfile\n");
|
||||
}
|
||||
} else {
|
||||
classname = strdup(name);
|
||||
if ( classname == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
}
|
||||
|
||||
*new_class_data_len = 0;
|
||||
*new_class_data = NULL;
|
||||
|
||||
/* The tracker class itself? */
|
||||
if ( interested((char*)classname, "", gdata->include, gdata->exclude)
|
||||
&& strcmp(classname, STRING(MTRACE_class)) != 0 ) {
|
||||
jint cnum;
|
||||
int system_class;
|
||||
unsigned char *new_image;
|
||||
long new_length;
|
||||
ClassInfo *cp;
|
||||
|
||||
/* Get unique number for every class file image loaded */
|
||||
cnum = gdata->ccount++;
|
||||
|
||||
/* Save away class information */
|
||||
if ( gdata->classes == NULL ) {
|
||||
gdata->classes = (ClassInfo*)malloc(
|
||||
gdata->ccount*sizeof(ClassInfo));
|
||||
} else {
|
||||
gdata->classes = (ClassInfo*)
|
||||
realloc((void*)gdata->classes,
|
||||
gdata->ccount*sizeof(ClassInfo));
|
||||
}
|
||||
if ( gdata->classes == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
cp = gdata->classes + cnum;
|
||||
cp->name = (const char *)strdup(classname);
|
||||
if ( cp->name == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
cp->calls = 0;
|
||||
cp->mcount = 0;
|
||||
cp->methods = NULL;
|
||||
|
||||
/* Is it a system class? If the class load is before VmStart
|
||||
* then we will consider it a system class that should
|
||||
* be treated carefully. (See java_crw_demo)
|
||||
*/
|
||||
system_class = 0;
|
||||
if ( !gdata->vm_is_started ) {
|
||||
system_class = 1;
|
||||
}
|
||||
|
||||
new_image = NULL;
|
||||
new_length = 0;
|
||||
|
||||
/* Call the class file reader/write demo code */
|
||||
java_crw_demo(cnum,
|
||||
classname,
|
||||
class_data,
|
||||
class_data_len,
|
||||
system_class,
|
||||
STRING(MTRACE_class), "L" STRING(MTRACE_class) ";",
|
||||
STRING(MTRACE_entry), "(II)V",
|
||||
STRING(MTRACE_exit), "(II)V",
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
&new_image,
|
||||
&new_length,
|
||||
NULL,
|
||||
&mnum_callbacks);
|
||||
|
||||
/* If we got back a new class image, return it back as "the"
|
||||
* new class image. This must be JVMTI Allocate space.
|
||||
*/
|
||||
if ( new_length > 0 ) {
|
||||
unsigned char *jvmti_space;
|
||||
|
||||
jvmti_space = (unsigned char *)allocate(jvmti, (jint)new_length);
|
||||
(void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length);
|
||||
*new_class_data_len = (jint)new_length;
|
||||
*new_class_data = jvmti_space; /* VM will deallocate */
|
||||
}
|
||||
|
||||
/* Always free up the space we get from java_crw_demo() */
|
||||
if ( new_image != NULL ) {
|
||||
(void)free((void*)new_image); /* Free malloc() space with free() */
|
||||
}
|
||||
}
|
||||
(void)free((void*)classname);
|
||||
}
|
||||
} exit_critical_section(jvmti);
|
||||
}
|
||||
|
||||
/* Parse the options for this mtrace agent */
|
||||
static void
|
||||
parse_agent_options(char *options)
|
||||
{
|
||||
char token[MAX_TOKEN_LENGTH];
|
||||
char *next;
|
||||
|
||||
gdata->max_count = 10; /* Default max=n */
|
||||
|
||||
/* Parse options and set flags in gdata */
|
||||
if ( options==NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the first token from the options string. */
|
||||
next = get_token(options, ",=", token, sizeof(token));
|
||||
|
||||
/* While not at the end of the options string, process this option. */
|
||||
while ( next != NULL ) {
|
||||
if ( strcmp(token,"help")==0 ) {
|
||||
stdout_message("The mtrace JVMTI demo agent\n");
|
||||
stdout_message("\n");
|
||||
stdout_message(" java -agent:mtrace[=options] ...\n");
|
||||
stdout_message("\n");
|
||||
stdout_message("The options are comma separated:\n");
|
||||
stdout_message("\t help\t\t\t Print help information\n");
|
||||
stdout_message("\t max=n\t\t Only list top n classes\n");
|
||||
stdout_message("\t include=item\t\t Only these classes/methods\n");
|
||||
stdout_message("\t exclude=item\t\t Exclude these classes/methods\n");
|
||||
stdout_message("\n");
|
||||
stdout_message("item\t Qualified class and/or method names\n");
|
||||
stdout_message("\t\t e.g. (*.<init>;Foobar.method;sun.*)\n");
|
||||
stdout_message("\n");
|
||||
exit(0);
|
||||
} else if ( strcmp(token,"max")==0 ) {
|
||||
char number[MAX_TOKEN_LENGTH];
|
||||
|
||||
/* Get the numeric option */
|
||||
next = get_token(next, ",=", number, (int)sizeof(number));
|
||||
/* Check for token scan error */
|
||||
if ( next==NULL ) {
|
||||
fatal_error("ERROR: max=n option error\n");
|
||||
}
|
||||
/* Save numeric value */
|
||||
gdata->max_count = atoi(number);
|
||||
} else if ( strcmp(token,"include")==0 ) {
|
||||
int used;
|
||||
int maxlen;
|
||||
|
||||
maxlen = MAX_METHOD_NAME_LENGTH;
|
||||
if ( gdata->include == NULL ) {
|
||||
gdata->include = (char*)calloc(maxlen+1, 1);
|
||||
used = 0;
|
||||
} else {
|
||||
used = (int)strlen(gdata->include);
|
||||
gdata->include[used++] = ',';
|
||||
gdata->include[used] = 0;
|
||||
gdata->include = (char*)
|
||||
realloc((void*)gdata->include, used+maxlen+1);
|
||||
}
|
||||
if ( gdata->include == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
/* Add this item to the list */
|
||||
next = get_token(next, ",=", gdata->include+used, maxlen);
|
||||
/* Check for token scan error */
|
||||
if ( next==NULL ) {
|
||||
fatal_error("ERROR: include option error\n");
|
||||
}
|
||||
} else if ( strcmp(token,"exclude")==0 ) {
|
||||
int used;
|
||||
int maxlen;
|
||||
|
||||
maxlen = MAX_METHOD_NAME_LENGTH;
|
||||
if ( gdata->exclude == NULL ) {
|
||||
gdata->exclude = (char*)calloc(maxlen+1, 1);
|
||||
used = 0;
|
||||
} else {
|
||||
used = (int)strlen(gdata->exclude);
|
||||
gdata->exclude[used++] = ',';
|
||||
gdata->exclude[used] = 0;
|
||||
gdata->exclude = (char*)
|
||||
realloc((void*)gdata->exclude, used+maxlen+1);
|
||||
}
|
||||
if ( gdata->exclude == NULL ) {
|
||||
fatal_error("ERROR: Out of malloc memory\n");
|
||||
}
|
||||
/* Add this item to the list */
|
||||
next = get_token(next, ",=", gdata->exclude+used, maxlen);
|
||||
/* Check for token scan error */
|
||||
if ( next==NULL ) {
|
||||
fatal_error("ERROR: exclude option error\n");
|
||||
}
|
||||
} else if ( token[0]!=0 ) {
|
||||
/* We got a non-empty token and we don't know what it is. */
|
||||
fatal_error("ERROR: Unknown option: %s\n", token);
|
||||
}
|
||||
/* Get the next token (returns NULL if there are no more) */
|
||||
next = get_token(next, ",=", token, sizeof(token));
|
||||
}
|
||||
}
|
||||
|
||||
/* Agent_OnLoad: This is called immediately after the shared library is
|
||||
* loaded. This is the first code executed.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
static GlobalAgentData data;
|
||||
jvmtiEnv *jvmti;
|
||||
jvmtiError error;
|
||||
jint res;
|
||||
jvmtiCapabilities capabilities;
|
||||
jvmtiEventCallbacks callbacks;
|
||||
|
||||
/* Setup initial global agent data area
|
||||
* Use of static/extern data should be handled carefully here.
|
||||
* We need to make sure that we are able to cleanup after ourselves
|
||||
* so anything allocated in this library needs to be freed in
|
||||
* the Agent_OnUnload() function.
|
||||
*/
|
||||
(void)memset((void*)&data, 0, sizeof(data));
|
||||
gdata = &data;
|
||||
|
||||
/* First thing we need to do is get the jvmtiEnv* or JVMTI environment */
|
||||
res = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1);
|
||||
if (res != JNI_OK) {
|
||||
/* This means that the VM was unable to obtain this version of the
|
||||
* JVMTI interface, this is a fatal error.
|
||||
*/
|
||||
fatal_error("ERROR: Unable to access JVMTI Version 1 (0x%x),"
|
||||
" is your JDK a 5.0 or newer version?"
|
||||
" JNIEnv's GetEnv() returned %d\n",
|
||||
JVMTI_VERSION_1, res);
|
||||
}
|
||||
|
||||
/* Here we save the jvmtiEnv* for Agent_OnUnload(). */
|
||||
gdata->jvmti = jvmti;
|
||||
|
||||
/* Parse any options supplied on java command line */
|
||||
parse_agent_options(options);
|
||||
|
||||
/* Immediately after getting the jvmtiEnv* we need to ask for the
|
||||
* capabilities this agent will need. In this case we need to make
|
||||
* sure that we can get all class load hooks.
|
||||
*/
|
||||
(void)memset(&capabilities,0, sizeof(capabilities));
|
||||
capabilities.can_generate_all_class_hook_events = 1;
|
||||
error = (*jvmti)->AddCapabilities(jvmti, &capabilities);
|
||||
check_jvmti_error(jvmti, error, "Unable to get necessary JVMTI capabilities.");
|
||||
|
||||
/* Next we need to provide the pointers to the callback functions to
|
||||
* to this jvmtiEnv*
|
||||
*/
|
||||
(void)memset(&callbacks,0, sizeof(callbacks));
|
||||
/* JVMTI_EVENT_VM_START */
|
||||
callbacks.VMStart = &cbVMStart;
|
||||
/* JVMTI_EVENT_VM_INIT */
|
||||
callbacks.VMInit = &cbVMInit;
|
||||
/* JVMTI_EVENT_VM_DEATH */
|
||||
callbacks.VMDeath = &cbVMDeath;
|
||||
/* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */
|
||||
callbacks.ClassFileLoadHook = &cbClassFileLoadHook;
|
||||
/* JVMTI_EVENT_THREAD_START */
|
||||
callbacks.ThreadStart = &cbThreadStart;
|
||||
/* JVMTI_EVENT_THREAD_END */
|
||||
callbacks.ThreadEnd = &cbThreadEnd;
|
||||
error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks));
|
||||
check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks");
|
||||
|
||||
/* At first the only initial events we are interested in are VM
|
||||
* initialization, VM death, and Class File Loads.
|
||||
* Once the VM is initialized we will request more events.
|
||||
*/
|
||||
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_START, (jthread)NULL);
|
||||
check_jvmti_error(jvmti, error, "Cannot set event notification");
|
||||
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_INIT, (jthread)NULL);
|
||||
check_jvmti_error(jvmti, error, "Cannot set event notification");
|
||||
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_DEATH, (jthread)NULL);
|
||||
check_jvmti_error(jvmti, error, "Cannot set event notification");
|
||||
error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread)NULL);
|
||||
check_jvmti_error(jvmti, error, "Cannot set event notification");
|
||||
|
||||
/* Here we create a raw monitor for our use in this agent to
|
||||
* protect critical sections of code.
|
||||
*/
|
||||
error = (*jvmti)->CreateRawMonitor(jvmti, "agent data", &(gdata->lock));
|
||||
check_jvmti_error(jvmti, error, "Cannot create raw monitor");
|
||||
|
||||
/* Add demo jar file to boot classpath */
|
||||
add_demo_jar_to_bootclasspath(jvmti, "mtrace");
|
||||
|
||||
/* We return JNI_OK to signify success */
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
/* Agent_OnUnload: This is called immediately before the shared library is
|
||||
* unloaded. This is the last code executed.
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
/* Make sure all malloc/calloc/strdup space is freed */
|
||||
if ( gdata->include != NULL ) {
|
||||
(void)free((void*)gdata->include);
|
||||
gdata->include = NULL;
|
||||
}
|
||||
if ( gdata->exclude != NULL ) {
|
||||
(void)free((void*)gdata->exclude);
|
||||
gdata->exclude = NULL;
|
||||
}
|
||||
if ( gdata->classes != NULL ) {
|
||||
int cnum;
|
||||
|
||||
for ( cnum = 0 ; cnum < gdata->ccount ; cnum++ ) {
|
||||
ClassInfo *cp;
|
||||
|
||||
cp = gdata->classes + cnum;
|
||||
(void)free((void*)cp->name);
|
||||
if ( cp->mcount > 0 ) {
|
||||
int mnum;
|
||||
|
||||
for ( mnum = 0 ; mnum < cp->mcount ; mnum++ ) {
|
||||
MethodInfo *mp;
|
||||
|
||||
mp = cp->methods + mnum;
|
||||
(void)free((void*)mp->name);
|
||||
(void)free((void*)mp->signature);
|
||||
}
|
||||
(void)free((void*)cp->methods);
|
||||
}
|
||||
}
|
||||
(void)free((void*)gdata->classes);
|
||||
gdata->classes = NULL;
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/* Primary mtrace #include file, should be included by most if not
|
||||
* all mtrace source files. Gives access to the global data structure
|
||||
* and all global macros.
|
||||
*/
|
||||
|
||||
#ifndef MTRACE_H
|
||||
#define MTRACE_H
|
||||
|
||||
/* Standard C functions used throughout. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* General JVM/Java functions, types and macros. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
/* Utility functions */
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
#endif
|
@ -1,163 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Sample GNU Makefile for building JVMTI Demo mtrace
|
||||
#
|
||||
# Example uses:
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparc]
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparcv9]
|
||||
# gnumake JDK=<java_home> OSNAME=linux [OPT=true]
|
||||
# gnumake JDK=<java_home> OSNAME=win32 [OPT=true]
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Source lists
|
||||
LIBNAME=mtrace
|
||||
SOURCES=mtrace.c ../agent_util/agent_util.c
|
||||
JAVA_SOURCES=Mtrace.java
|
||||
|
||||
# Name of jar file that needs to be created
|
||||
JARFILE=mtrace.jar
|
||||
|
||||
# Solaris Studio C Compiler Version 12.4
|
||||
ifeq ($(OSNAME), solaris)
|
||||
# Sun Solaris Compiler options needed
|
||||
COMMON_FLAGS=-mt -KPIC
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -Xa -v -xc99=%none
|
||||
# Check LIBARCH for any special compiler options
|
||||
LIBARCH=$(shell uname -p)
|
||||
ifeq ($(LIBARCH), sparc)
|
||||
COMMON_FLAGS+=-xarch=v8 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(LIBARCH), sparcv9)
|
||||
COMMON_FLAGS+=-xarch=v9 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-xO2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-z defs -ztext
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-L $(JDK)/jre/lib/$(LIBARCH) -ljava_crw_demo -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -G -o $@
|
||||
endif
|
||||
|
||||
# Linux GNU C Compiler
|
||||
ifeq ($(OSNAME), linux)
|
||||
# GNU Compiler options needed to build it
|
||||
COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-O2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-L $(JDK)/jre/lib/$(LIBARCH) -ljava_crw_demo -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -shared -o $@
|
||||
endif
|
||||
|
||||
# Windows Microsoft C/C++ Optimizing Compiler Version 12
|
||||
ifeq ($(OSNAME), win32)
|
||||
CC=cl
|
||||
# Compiler options needed to build it
|
||||
COMMON_FLAGS=-Gy -DWIN32
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+=-W0 -WX
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS= -Ox -Op -Zi $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS= -Od -Zi $(COMMON_FLAGS)
|
||||
endif
|
||||
# Add in java_crw_demo obj file on windows (easier)
|
||||
SOURCES+=../java_crw_demo/java_crw_demo.c
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.obj)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=$(LIBNAME).dll
|
||||
LDFLAGS=
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=$(JDK)/
|
||||
# Building a shared library
|
||||
LINK_SHARED=link -dll -out:$@
|
||||
endif
|
||||
|
||||
# Common -I options
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../agent_util
|
||||
CFLAGS += -I../java_crw_demo
|
||||
CFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME)
|
||||
|
||||
# Default rule (build both native library and jar file)
|
||||
all: $(LIBRARY) $(JARFILE)
|
||||
|
||||
# Build native library
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
|
||||
|
||||
# Build jar file
|
||||
$(JARFILE): $(JAVA_SOURCES)
|
||||
rm -f -r classes
|
||||
mkdir -p classes
|
||||
$(JDK)/bin/javac -d classes $(JAVA_SOURCES)
|
||||
(cd classes; $(JDK)/bin/jar cf ../$@ *)
|
||||
|
||||
# Cleanup the built bits
|
||||
clean:
|
||||
rm -f -r classes
|
||||
rm -f $(LIBRARY) $(JARFILE) $(OBJECTS)
|
||||
|
||||
# Simple tester
|
||||
test: all
|
||||
LD_LIBRARY_PATH=. $(JDK)/bin/java -agentlib:$(LIBNAME) -Xbootclasspath/a:./$(JARFILE) -version
|
||||
|
||||
# Compilation rule only needed on Windows
|
||||
ifeq ($(OSNAME), win32)
|
||||
%.obj: %.c
|
||||
$(COMPILE.c) $<
|
||||
endif
|
||||
|
@ -1,43 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
versionCheck
|
||||
|
||||
This agent library just makes some simple calls and checks
|
||||
the version of the interface being used to build the agent,
|
||||
with that supplied by the VM at runtime.
|
||||
|
||||
You can use this agent library as follows:
|
||||
|
||||
java -agentlib:versionCheck ...
|
||||
|
||||
See ${JAVA_HOME}/demo/jvmti/index.html for help running and building agents.
|
||||
|
@ -1,148 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Sample GNU Makefile for building JVMTI Demo versionCheck
|
||||
#
|
||||
# Example uses:
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparc]
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparcv9]
|
||||
# gnumake JDK=<java_home> OSNAME=linux [OPT=true]
|
||||
# gnumake JDK=<java_home> OSNAME=win32 [OPT=true]
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Source lists
|
||||
LIBNAME=versionCheck
|
||||
SOURCES=versionCheck.c ../agent_util/agent_util.c
|
||||
|
||||
# Solaris Studio C Compiler Version 12.4
|
||||
ifeq ($(OSNAME), solaris)
|
||||
# Sun Solaris Compiler options needed
|
||||
COMMON_FLAGS=-mt -KPIC
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -Xa -v -xc99=%none
|
||||
# Check LIBARCH for any special compiler options
|
||||
LIBARCH=$(shell uname -p)
|
||||
ifeq ($(LIBARCH), sparc)
|
||||
COMMON_FLAGS+=-xarch=v8 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(LIBARCH), sparcv9)
|
||||
COMMON_FLAGS+=-xarch=v9 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-xO2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-z defs -ztext
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES= -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -G -o $@
|
||||
endif
|
||||
|
||||
# Linux GNU C Compiler
|
||||
ifeq ($(OSNAME), linux)
|
||||
# GNU Compiler options needed to build it
|
||||
COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS=-O2 $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=-lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.c) -shared -o $@
|
||||
endif
|
||||
|
||||
# Windows Microsoft C/C++ Optimizing Compiler Version 12
|
||||
ifeq ($(OSNAME), win32)
|
||||
CC=cl
|
||||
# Compiler options needed to build it
|
||||
COMMON_FLAGS=-Gy -DWIN32
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+=-W0 -WX
|
||||
ifeq ($(OPT), true)
|
||||
CFLAGS= -Ox -Op -Zi $(COMMON_FLAGS)
|
||||
else
|
||||
CFLAGS= -Od -Zi $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.c=%.obj)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=$(LIBNAME).dll
|
||||
LDFLAGS=
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=
|
||||
# Building a shared library
|
||||
LINK_SHARED=link -dll -out:$@
|
||||
endif
|
||||
|
||||
# Common -I options
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../agent_util
|
||||
CFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME)
|
||||
|
||||
# Default rule
|
||||
all: $(LIBRARY)
|
||||
|
||||
# Build native library
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
|
||||
|
||||
# Cleanup the built bits
|
||||
clean:
|
||||
rm -f $(LIBRARY) $(OBJECTS)
|
||||
|
||||
# Simple tester
|
||||
test: all
|
||||
LD_LIBRARY_PATH=`pwd` $(JDK)/bin/java -agentlib:$(LIBNAME) -version
|
||||
|
||||
# Compilation rule only needed on Windows
|
||||
ifeq ($(OSNAME), win32)
|
||||
%.obj: %.c
|
||||
$(COMPILE.c) $<
|
||||
endif
|
||||
|
@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
/* Create major.minor.micro version string */
|
||||
static void
|
||||
version_check(jint cver, jint rver)
|
||||
{
|
||||
jint cmajor, cminor, cmicro;
|
||||
jint rmajor, rminor, rmicro;
|
||||
|
||||
cmajor = (cver & JVMTI_VERSION_MASK_MAJOR) >> JVMTI_VERSION_SHIFT_MAJOR;
|
||||
cminor = (cver & JVMTI_VERSION_MASK_MINOR) >> JVMTI_VERSION_SHIFT_MINOR;
|
||||
cmicro = (cver & JVMTI_VERSION_MASK_MICRO) >> JVMTI_VERSION_SHIFT_MICRO;
|
||||
rmajor = (rver & JVMTI_VERSION_MASK_MAJOR) >> JVMTI_VERSION_SHIFT_MAJOR;
|
||||
rminor = (rver & JVMTI_VERSION_MASK_MINOR) >> JVMTI_VERSION_SHIFT_MINOR;
|
||||
rmicro = (rver & JVMTI_VERSION_MASK_MICRO) >> JVMTI_VERSION_SHIFT_MICRO;
|
||||
stdout_message("Compile Time JVMTI Version: %d.%d.%d (0x%08x)\n",
|
||||
cmajor, cminor, cmicro, cver);
|
||||
stdout_message("Run Time JVMTI Version: %d.%d.%d (0x%08x)\n",
|
||||
rmajor, rminor, rmicro, rver);
|
||||
if ( (cmajor > rmajor) || (cmajor == rmajor && cminor > rminor) ) {
|
||||
fatal_error(
|
||||
"ERROR: Compile Time JVMTI and Run Time JVMTI are incompatible\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback for JVMTI_EVENT_VM_INIT */
|
||||
static void JNICALL
|
||||
vm_init(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
jvmtiError err;
|
||||
jint runtime_version;
|
||||
|
||||
/* The exact JVMTI version doesn't have to match, however this
|
||||
* code demonstrates how you can check that the JVMTI version seen
|
||||
* in the jvmti.h include file matches that being supplied at runtime
|
||||
* by the VM.
|
||||
*/
|
||||
err = (*jvmti)->GetVersionNumber(jvmti, &runtime_version);
|
||||
check_jvmti_error(jvmti, err, "get version number");
|
||||
version_check(JVMTI_VERSION, runtime_version);
|
||||
}
|
||||
|
||||
/* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jint rc;
|
||||
jvmtiError err;
|
||||
jvmtiEventCallbacks callbacks;
|
||||
jvmtiEnv *jvmti;
|
||||
|
||||
/* Get JVMTI environment */
|
||||
rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION);
|
||||
if (rc != JNI_OK) {
|
||||
fatal_error("ERROR: Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set callbacks and enable event notifications */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.VMInit = &vm_init;
|
||||
err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
|
||||
check_jvmti_error(jvmti, err, "set event callbacks");
|
||||
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_INIT, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
#include "Monitor.hpp"
|
||||
#include "Thread.hpp"
|
||||
#include "Agent.hpp"
|
||||
|
||||
/* Implementation of the Agent class */
|
||||
|
||||
/* Given a jvmtiEnv* and jthread, find the Thread instance */
|
||||
Thread *
|
||||
Agent::get_thread(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
jvmtiError err;
|
||||
Thread *t;
|
||||
|
||||
/* This should always be in the Thread Local Storage */
|
||||
t = NULL;
|
||||
err = jvmti->GetThreadLocalStorage(thread, (void**)&t);
|
||||
check_jvmti_error(jvmti, err, "get thread local storage");
|
||||
if ( t == NULL ) {
|
||||
/* This jthread has never been seen before? */
|
||||
stdout_message("WARNING: Never before seen jthread?\n");
|
||||
t = new Thread(jvmti, env, thread);
|
||||
err = jvmti->SetThreadLocalStorage(thread, (const void*)t);
|
||||
check_jvmti_error(jvmti, err, "set thread local storage");
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Given a jvmtiEnv* and jobject, find the Monitor instance or create one */
|
||||
Monitor *
|
||||
Agent::get_monitor(jvmtiEnv *jvmti, JNIEnv *env, jobject object)
|
||||
{
|
||||
jvmtiError err;
|
||||
Monitor *m;
|
||||
jlong tag;
|
||||
|
||||
m = NULL;
|
||||
tag = (jlong)0;
|
||||
err = jvmti->GetTag(object, &tag);
|
||||
check_jvmti_error(jvmti, err, "get tag");
|
||||
/*LINTED*/
|
||||
m = (Monitor *)(void *)(ptrdiff_t)tag;
|
||||
if ( m == NULL ) {
|
||||
m = new Monitor(jvmti, env, object);
|
||||
/* Save monitor on list */
|
||||
if (monitor_count == monitor_list_size) {
|
||||
monitor_list_size += monitor_list_grow_size;
|
||||
monitor_list = (Monitor**)realloc((void*)monitor_list,
|
||||
(monitor_list_size)*(int)sizeof(Monitor*));
|
||||
}
|
||||
monitor_list[monitor_count] = m;
|
||||
m->set_slot(monitor_count);
|
||||
monitor_count++;
|
||||
/*LINTED*/
|
||||
tag = (jlong)(ptrdiff_t)(void *)m;
|
||||
err = jvmti->SetTag(object, tag);
|
||||
check_jvmti_error(jvmti, err, "set tag");
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/* VM initialization and VM death calls to Agent */
|
||||
Agent::Agent(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
stdout_message("Agent created..\n");
|
||||
stdout_message("VMInit...\n");
|
||||
/* Start monitor list */
|
||||
monitor_count = 0;
|
||||
monitor_list_size = initial_monitor_list_size;
|
||||
monitor_list = (Monitor**)
|
||||
malloc(monitor_list_size*(int)sizeof(Monitor*));
|
||||
}
|
||||
|
||||
Agent::~Agent()
|
||||
{
|
||||
stdout_message("Agent reclaimed..\n");
|
||||
}
|
||||
|
||||
void Agent::vm_death(jvmtiEnv *jvmti, JNIEnv *env)
|
||||
{
|
||||
/* Delete all Monitors we allocated */
|
||||
for ( int i = 0; i < (int)monitor_count; i++ ) {
|
||||
delete monitor_list[i];
|
||||
}
|
||||
free(monitor_list);
|
||||
/* Print death message */
|
||||
stdout_message("VMDeath...\n");
|
||||
}
|
||||
|
||||
/* Thread start event, setup a new thread */
|
||||
void Agent::thread_start(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
jvmtiError err;
|
||||
Thread *t;
|
||||
|
||||
/* Allocate a new Thread instance, put it in the Thread Local
|
||||
* Storage for easy access later.
|
||||
*/
|
||||
t = new Thread(jvmti, env, thread);
|
||||
err = jvmti->SetThreadLocalStorage(thread, (const void*)t);
|
||||
check_jvmti_error(jvmti, err, "set thread local storage");
|
||||
}
|
||||
|
||||
|
||||
/* Thread end event, we need to reclaim the space */
|
||||
void Agent::thread_end(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
jvmtiError err;
|
||||
Thread *t;
|
||||
|
||||
/* Find the thread */
|
||||
t = get_thread(jvmti, env, thread);
|
||||
|
||||
/* Clear out the Thread Local Storage */
|
||||
err = jvmti->SetThreadLocalStorage(thread, (const void*)NULL);
|
||||
check_jvmti_error(jvmti, err, "set thread local storage");
|
||||
|
||||
/* Reclaim the C++ object space */
|
||||
delete t;
|
||||
}
|
||||
|
||||
/* Monitor contention begins for a thread. */
|
||||
void Agent::monitor_contended_enter(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object)
|
||||
{
|
||||
get_monitor(jvmti, env, object)->contended();
|
||||
get_thread(jvmti, env, thread)->
|
||||
monitor_contended_enter(jvmti, env, thread, object);
|
||||
}
|
||||
|
||||
/* Monitor contention ends for a thread. */
|
||||
void Agent::monitor_contended_entered(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object)
|
||||
{
|
||||
/* Do nothing for now */
|
||||
}
|
||||
|
||||
/* Monitor wait begins for a thread. */
|
||||
void Agent::monitor_wait(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jlong timeout)
|
||||
{
|
||||
get_monitor(jvmti, env, object)->waited();
|
||||
get_thread(jvmti, env, thread)->
|
||||
monitor_wait(jvmti, env, thread, object, timeout);
|
||||
}
|
||||
|
||||
/* Monitor wait ends for a thread. */
|
||||
void Agent::monitor_waited(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jboolean timed_out)
|
||||
{
|
||||
if ( timed_out ) {
|
||||
get_monitor(jvmti, env, object)->timeout();
|
||||
}
|
||||
get_thread(jvmti, env, thread)->
|
||||
monitor_waited(jvmti, env, thread, object, timed_out);
|
||||
}
|
||||
|
||||
/* A tagged object has been freed */
|
||||
void Agent::object_free(jvmtiEnv* jvmti, jlong tag)
|
||||
{
|
||||
/* We just cast the tag to a C++ pointer and delete it.
|
||||
* we know it can only be a Monitor *.
|
||||
*/
|
||||
Monitor *m;
|
||||
/*LINTED*/
|
||||
m = (Monitor *)(ptrdiff_t)tag;
|
||||
if (monitor_count > 1) {
|
||||
/* Move the last element to this Monitor's slot */
|
||||
int slot = m->get_slot();
|
||||
Monitor *last = monitor_list[monitor_count-1];
|
||||
monitor_list[slot] = last;
|
||||
last->set_slot(slot);
|
||||
}
|
||||
monitor_count--;
|
||||
delete m;
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/* C++ Agent class */
|
||||
|
||||
class Agent {
|
||||
|
||||
private:
|
||||
enum {
|
||||
initial_monitor_list_size = 64,
|
||||
monitor_list_grow_size = 16
|
||||
};
|
||||
Monitor **monitor_list;
|
||||
unsigned monitor_list_size;
|
||||
unsigned monitor_count;
|
||||
Thread *get_thread(jvmtiEnv *jvmti, JNIEnv *env, jthread thread);
|
||||
Monitor *get_monitor(jvmtiEnv *jvmti, JNIEnv *env, jobject object);
|
||||
|
||||
public:
|
||||
Agent(jvmtiEnv *jvmti, JNIEnv *env, jthread thread);
|
||||
~Agent();
|
||||
void vm_death(jvmtiEnv *jvmti, JNIEnv *env);
|
||||
void thread_start(jvmtiEnv *jvmti, JNIEnv *env, jthread thread);
|
||||
void thread_end(jvmtiEnv *jvmti, JNIEnv *env, jthread thread);
|
||||
void monitor_contended_enter(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object);
|
||||
void monitor_contended_entered(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object);
|
||||
void monitor_wait(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jlong timeout);
|
||||
void monitor_waited(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jboolean timed_out);
|
||||
void object_free(jvmtiEnv* jvmti, jlong tag);
|
||||
|
||||
};
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
#include "Monitor.hpp"
|
||||
|
||||
/* Implementation of the Monitor class */
|
||||
|
||||
Monitor::Monitor(jvmtiEnv *jvmti, JNIEnv *env, jobject object)
|
||||
{
|
||||
jvmtiError err;
|
||||
jclass klass;
|
||||
char *signature;
|
||||
|
||||
/* Clear counters */
|
||||
contends = 0;
|
||||
waits = 0;
|
||||
timeouts = 0;
|
||||
|
||||
/* Get the class name for this monitor object */
|
||||
(void)strcpy(name, "Unknown");
|
||||
klass = env->GetObjectClass(object);
|
||||
if ( klass == NULL ) {
|
||||
fatal_error("ERROR: Cannot find jclass from jobject\n");
|
||||
}
|
||||
err = jvmti->GetClassSignature(klass, &signature, NULL);
|
||||
check_jvmti_error(jvmti, err, "get class signature");
|
||||
if ( signature != NULL ) {
|
||||
(void)strncpy(name, signature, (int)sizeof(name)-1);
|
||||
deallocate(jvmti, signature);
|
||||
}
|
||||
}
|
||||
|
||||
Monitor::~Monitor()
|
||||
{
|
||||
stdout_message("Monitor %s summary: %d contends, %d waits, %d timeouts\n",
|
||||
name, contends, waits, timeouts);
|
||||
}
|
||||
|
||||
int Monitor::get_slot()
|
||||
{
|
||||
return slot;
|
||||
}
|
||||
|
||||
void Monitor::set_slot(int aslot)
|
||||
{
|
||||
slot = aslot;
|
||||
}
|
||||
|
||||
void Monitor::contended()
|
||||
{
|
||||
contends++;
|
||||
}
|
||||
|
||||
void Monitor::waited()
|
||||
{
|
||||
waits++;
|
||||
}
|
||||
|
||||
void Monitor::timeout()
|
||||
{
|
||||
timeouts++;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
#define Monitor WaiterMonitor
|
||||
#endif
|
||||
|
||||
|
||||
/* C++ Monitor class */
|
||||
|
||||
class Monitor {
|
||||
|
||||
private:
|
||||
char name[64];
|
||||
int slot;
|
||||
unsigned contends;
|
||||
unsigned waits;
|
||||
unsigned timeouts;
|
||||
|
||||
public:
|
||||
Monitor(jvmtiEnv *jvmti, JNIEnv *env, jobject object);
|
||||
~Monitor();
|
||||
int get_slot();
|
||||
void set_slot(int i);
|
||||
void contended();
|
||||
void waited();
|
||||
void timeout();
|
||||
|
||||
};
|
@ -1,46 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
waiters
|
||||
|
||||
This agent library can be used to track threads that wait on monitors.
|
||||
This agent is written in C++.
|
||||
|
||||
You can use this agent library as follows:
|
||||
|
||||
java -agentlib:waiters ...
|
||||
|
||||
To get help on the available options try:
|
||||
|
||||
java -agentlib:waiters=help
|
||||
|
||||
See ${JAVA_HOME}/demo/jvmti/index.html for help running and building agents.
|
||||
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
#define Thread WaiterThread
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
#include "Thread.hpp"
|
||||
|
||||
/* Implementation of the Thread class */
|
||||
|
||||
Thread::Thread(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
jvmtiError err;
|
||||
jvmtiThreadInfo info;
|
||||
|
||||
/* Get and save the name of the thread */
|
||||
info.name = NULL;
|
||||
(void)strcpy(name, "Unknown");
|
||||
err = jvmti->GetThreadInfo(thread, &info);
|
||||
check_jvmti_error(jvmti, err, "get thread info");
|
||||
if ( info.name != NULL ) {
|
||||
(void)strncpy(name, info.name, (int)sizeof(name)-1);
|
||||
name[(int)sizeof(name)-1] = 0;
|
||||
deallocate(jvmti, info.name);
|
||||
}
|
||||
|
||||
/* Clear thread counters */
|
||||
contends = 0;
|
||||
waits = 0;
|
||||
timeouts = 0;
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
/* Send out summary message */
|
||||
stdout_message("Thread %s summary: %d waits plus %d contended\n",
|
||||
name, waits, contends);
|
||||
}
|
||||
|
||||
void Thread::monitor_contended_enter(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object)
|
||||
{
|
||||
contends++;
|
||||
}
|
||||
|
||||
void Thread::monitor_wait(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jlong timeout)
|
||||
{
|
||||
waits++;
|
||||
}
|
||||
|
||||
void Thread::monitor_waited(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jboolean timed_out)
|
||||
{
|
||||
if ( timed_out ) {
|
||||
timeouts++;
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/* C++ Thread class */
|
||||
|
||||
class Thread {
|
||||
|
||||
private:
|
||||
char name[64];
|
||||
unsigned contends;
|
||||
unsigned waits;
|
||||
unsigned timeouts;
|
||||
|
||||
public:
|
||||
Thread(jvmtiEnv *jvmti, JNIEnv *env, jthread thread);
|
||||
~Thread();
|
||||
void monitor_contended_enter(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object);
|
||||
void monitor_wait(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jlong timeout);
|
||||
void monitor_waited(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jboolean timed_out);
|
||||
|
||||
};
|
@ -1,149 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Sample GNU Makefile for building JVMTI Demo waiters
|
||||
#
|
||||
# Example uses:
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparc]
|
||||
# gnumake JDK=<java_home> OSNAME=solaris [OPT=true] [LIBARCH=sparcv9]
|
||||
# gnumake JDK=<java_home> OSNAME=linux [OPT=true]
|
||||
# gnumake JDK=<java_home> OSNAME=win32 [OPT=true]
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Source lists
|
||||
LIBNAME=waiters
|
||||
SOURCES=waiters.cpp Agent.cpp Thread.cpp Monitor.cpp ../agent_util/agent_util.c
|
||||
|
||||
# Solaris Sun C Compiler Version 5.5
|
||||
ifeq ($(OSNAME), solaris)
|
||||
# Tell gnumake which compilers to use
|
||||
CC=cc
|
||||
CXX=CC
|
||||
# Sun Solaris Compiler options needed
|
||||
COMMON_FLAGS=-mt -KPIC
|
||||
# Check LIBARCH for any special compiler options
|
||||
LIBARCH=$(shell uname -p)
|
||||
ifeq ($(LIBARCH), sparc)
|
||||
COMMON_FLAGS+=-xarch=v8 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(LIBARCH), sparcv9)
|
||||
COMMON_FLAGS+=-xarch=v9 -xregs=no%appl
|
||||
endif
|
||||
ifeq ($(OPT), true)
|
||||
CXXFLAGS=-xO2 $(COMMON_FLAGS)
|
||||
else
|
||||
CXXFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.cpp=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-z defs -ztext
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES= -lc
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.cc) -G -o $@
|
||||
endif
|
||||
|
||||
# Linux GNU C Compiler
|
||||
ifeq ($(OSNAME), linux)
|
||||
# GNU Compiler options needed to build it
|
||||
COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses
|
||||
ifeq ($(OPT), true)
|
||||
CXXFLAGS=-O2 $(COMMON_FLAGS)
|
||||
else
|
||||
CXXFLAGS=-g $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.cpp=%.o)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=lib$(LIBNAME).so
|
||||
LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=
|
||||
# Building a shared library
|
||||
LINK_SHARED=$(LINK.cc) -shared -o $@
|
||||
endif
|
||||
|
||||
# Windows Microsoft C/C++ Optimizing Compiler Version 12
|
||||
ifeq ($(OSNAME), win32)
|
||||
CC=cl
|
||||
# Compiler options needed to build it
|
||||
COMMON_FLAGS=-Gy -DWIN32
|
||||
# Options that help find errors
|
||||
COMMON_FLAGS+=-W0 -WX
|
||||
ifeq ($(OPT), true)
|
||||
CXXFLAGS= -Ox -Op -Zi $(COMMON_FLAGS)
|
||||
else
|
||||
CXXFLAGS= -Od -Zi $(COMMON_FLAGS)
|
||||
endif
|
||||
# Object files needed to create library
|
||||
OBJECTS=$(SOURCES:%.cpp=%.obj)
|
||||
# Library name and options needed to build it
|
||||
LIBRARY=$(LIBNAME).dll
|
||||
LDFLAGS=
|
||||
# Libraries we are dependent on
|
||||
LIBRARIES=
|
||||
# Building a shared library
|
||||
LINK_SHARED=link -dll -out:$@
|
||||
endif
|
||||
|
||||
# Common -I options
|
||||
CXXFLAGS += -I.
|
||||
CXXFLAGS += -I../agent_util
|
||||
CXXFLAGS += -I$(JDK)/include -I$(JDK)/include/$(OSNAME)
|
||||
|
||||
# Default rule
|
||||
all: $(LIBRARY)
|
||||
|
||||
# Build native library
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
|
||||
|
||||
# Cleanup the built bits
|
||||
clean:
|
||||
rm -f $(LIBRARY) $(OBJECTS)
|
||||
|
||||
# Simple tester
|
||||
test: all
|
||||
LD_LIBRARY_PATH=`pwd` $(JDK)/bin/java -agentlib:$(LIBNAME) -version
|
||||
|
||||
# Compilation rule only needed on Windows
|
||||
ifeq ($(OSNAME), win32)
|
||||
%.obj: %.cpp
|
||||
$(COMPILE.cc) $<
|
||||
endif
|
||||
|
@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/* Example of using JVMTI events:
|
||||
* JVMTI_EVENT_VM_INIT
|
||||
* JVMTI_EVENT_VM_DEATH
|
||||
* JVMTI_EVENT_THREAD_START
|
||||
* JVMTI_EVENT_THREAD_END
|
||||
* JVMTI_EVENT_MONITOR_CONTENDED_ENTER
|
||||
* JVMTI_EVENT_MONITOR_WAIT
|
||||
* JVMTI_EVENT_MONITOR_WAITED
|
||||
* JVMTI_EVENT_OBJECT_FREE
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
#include "Monitor.hpp"
|
||||
#include "Thread.hpp"
|
||||
#include "Agent.hpp"
|
||||
|
||||
static jrawMonitorID vm_death_lock;
|
||||
static jboolean vm_death_active;
|
||||
|
||||
/* Given a jvmtiEnv*, return the C++ Agent class instance */
|
||||
static Agent *
|
||||
get_agent(jvmtiEnv *jvmti)
|
||||
{
|
||||
jvmtiError err;
|
||||
Agent *agent;
|
||||
|
||||
agent = NULL;
|
||||
err = jvmti->GetEnvironmentLocalStorage((void**)&agent);
|
||||
check_jvmti_error(jvmti, err, "get env local storage");
|
||||
if ( agent == NULL ) {
|
||||
/* This should never happen, but we should check */
|
||||
fatal_error("ERROR: GetEnvironmentLocalStorage() returned NULL");
|
||||
}
|
||||
return agent;
|
||||
}
|
||||
|
||||
/* Enter raw monitor */
|
||||
static void
|
||||
menter(jvmtiEnv *jvmti, jrawMonitorID rmon)
|
||||
{
|
||||
jvmtiError err;
|
||||
|
||||
err = jvmti->RawMonitorEnter(rmon);
|
||||
check_jvmti_error(jvmti, err, "raw monitor enter");
|
||||
}
|
||||
|
||||
/* Exit raw monitor */
|
||||
static void
|
||||
mexit(jvmtiEnv *jvmti, jrawMonitorID rmon)
|
||||
{
|
||||
jvmtiError err;
|
||||
|
||||
err = jvmti->RawMonitorExit(rmon);
|
||||
check_jvmti_error(jvmti, err, "raw monitor exit");
|
||||
}
|
||||
|
||||
|
||||
/* All callbacks need to be extern "C" */
|
||||
extern "C" {
|
||||
static void JNICALL
|
||||
vm_init(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
jvmtiError err;
|
||||
Agent *agent;
|
||||
|
||||
/* Create raw monitor to protect against threads running after death */
|
||||
err = jvmti->CreateRawMonitor("Waiters vm_death lock", &vm_death_lock);
|
||||
check_jvmti_error(jvmti, err, "create raw monitor");
|
||||
vm_death_active = JNI_FALSE;
|
||||
|
||||
/* Create an Agent instance, set JVMTI Local Storage */
|
||||
agent = new Agent(jvmti, env, thread);
|
||||
err = jvmti->SetEnvironmentLocalStorage((const void*)agent);
|
||||
check_jvmti_error(jvmti, err, "set env local storage");
|
||||
|
||||
/* Enable all other events we want */
|
||||
err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_DEATH, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
|
||||
JVMTI_EVENT_THREAD_START, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
|
||||
JVMTI_EVENT_THREAD_END, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
|
||||
JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
|
||||
JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
|
||||
JVMTI_EVENT_MONITOR_WAIT, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
|
||||
JVMTI_EVENT_MONITOR_WAITED, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
|
||||
JVMTI_EVENT_OBJECT_FREE, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
}
|
||||
static void JNICALL
|
||||
vm_death(jvmtiEnv *jvmti, JNIEnv *env)
|
||||
{
|
||||
jvmtiError err;
|
||||
Agent *agent;
|
||||
|
||||
/* Block all callbacks */
|
||||
menter(jvmti, vm_death_lock); {
|
||||
/* Set flag for other callbacks */
|
||||
vm_death_active = JNI_TRUE;
|
||||
|
||||
/* Inform Agent instance of VM_DEATH */
|
||||
agent = get_agent(jvmti);
|
||||
agent->vm_death(jvmti, env);
|
||||
|
||||
/* Reclaim space of Agent */
|
||||
err = jvmti->SetEnvironmentLocalStorage((const void*)NULL);
|
||||
check_jvmti_error(jvmti, err, "set env local storage");
|
||||
delete agent;
|
||||
} mexit(jvmti, vm_death_lock);
|
||||
|
||||
}
|
||||
static void JNICALL
|
||||
thread_start(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
menter(jvmti, vm_death_lock); {
|
||||
if ( !vm_death_active ) {
|
||||
get_agent(jvmti)->thread_start(jvmti, env, thread);
|
||||
}
|
||||
} mexit(jvmti, vm_death_lock);
|
||||
}
|
||||
static void JNICALL
|
||||
thread_end(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
{
|
||||
menter(jvmti, vm_death_lock); {
|
||||
if ( !vm_death_active ) {
|
||||
get_agent(jvmti)->thread_end(jvmti, env, thread);
|
||||
}
|
||||
} mexit(jvmti, vm_death_lock);
|
||||
}
|
||||
static void JNICALL
|
||||
monitor_contended_enter(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object)
|
||||
{
|
||||
menter(jvmti, vm_death_lock); {
|
||||
if ( !vm_death_active ) {
|
||||
get_agent(jvmti)->monitor_contended_enter(jvmti, env,
|
||||
thread, object);
|
||||
}
|
||||
} mexit(jvmti, vm_death_lock);
|
||||
}
|
||||
static void JNICALL
|
||||
monitor_contended_entered(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object)
|
||||
{
|
||||
menter(jvmti, vm_death_lock); {
|
||||
if ( !vm_death_active ) {
|
||||
get_agent(jvmti)->monitor_contended_entered(jvmti, env,
|
||||
thread, object);
|
||||
}
|
||||
} mexit(jvmti, vm_death_lock);
|
||||
}
|
||||
static void JNICALL
|
||||
monitor_wait(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jlong timeout)
|
||||
{
|
||||
menter(jvmti, vm_death_lock); {
|
||||
if ( !vm_death_active ) {
|
||||
get_agent(jvmti)->monitor_wait(jvmti, env, thread,
|
||||
object, timeout);
|
||||
}
|
||||
} mexit(jvmti, vm_death_lock);
|
||||
}
|
||||
static void JNICALL
|
||||
monitor_waited(jvmtiEnv* jvmti, JNIEnv *env,
|
||||
jthread thread, jobject object, jboolean timed_out)
|
||||
{
|
||||
menter(jvmti, vm_death_lock); {
|
||||
if ( !vm_death_active ) {
|
||||
get_agent(jvmti)->monitor_waited(jvmti, env, thread,
|
||||
object, timed_out);
|
||||
}
|
||||
} mexit(jvmti, vm_death_lock);
|
||||
}
|
||||
static void JNICALL
|
||||
object_free(jvmtiEnv* jvmti, jlong tag)
|
||||
{
|
||||
menter(jvmti, vm_death_lock); {
|
||||
if ( !vm_death_active ) {
|
||||
get_agent(jvmti)->object_free(jvmti, tag);
|
||||
}
|
||||
} mexit(jvmti, vm_death_lock);
|
||||
}
|
||||
|
||||
/* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jvmtiEnv *jvmti;
|
||||
jint rc;
|
||||
jvmtiError err;
|
||||
jvmtiCapabilities capabilities;
|
||||
jvmtiEventCallbacks callbacks;
|
||||
|
||||
/* Get JVMTI environment */
|
||||
rc = vm->GetEnv((void **)&jvmti, JVMTI_VERSION);
|
||||
if (rc != JNI_OK) {
|
||||
fatal_error("ERROR: Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get/Add JVMTI capabilities */
|
||||
(void)memset(&capabilities, 0, sizeof(capabilities));
|
||||
capabilities.can_generate_monitor_events = 1;
|
||||
capabilities.can_get_monitor_info = 1;
|
||||
capabilities.can_tag_objects = 1;
|
||||
capabilities.can_generate_object_free_events = 1;
|
||||
err = jvmti->AddCapabilities(&capabilities);
|
||||
check_jvmti_error(jvmti, err, "add capabilities");
|
||||
|
||||
/* Set all callbacks and enable VM_INIT event notification */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.VMInit = &vm_init;
|
||||
callbacks.VMDeath = &vm_death;
|
||||
callbacks.ThreadStart = &thread_start;
|
||||
callbacks.ThreadEnd = &thread_end;
|
||||
callbacks.MonitorContendedEnter = &monitor_contended_enter;
|
||||
callbacks.MonitorContendedEntered = &monitor_contended_entered;
|
||||
callbacks.MonitorWait = &monitor_wait;
|
||||
callbacks.MonitorWaited = &monitor_waited;
|
||||
callbacks.ObjectFree = &object_free;
|
||||
err = jvmti->SetEventCallbacks(&callbacks, (jint)sizeof(callbacks));
|
||||
check_jvmti_error(jvmti, err, "set event callbacks");
|
||||
err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
|
||||
JVMTI_EVENT_VM_INIT, NULL);
|
||||
check_jvmti_error(jvmti, err, "set event notify");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
||||
|
||||
} /* of extern "C" */
|
@ -1,214 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This Deadlock class demonstrates the capability of performing
|
||||
* deadlock detection programmatically within the application using
|
||||
* the java.lang.management API.
|
||||
*
|
||||
* See ThreadMonitor.java for the use of java.lang.management.ThreadMXBean
|
||||
* API.
|
||||
*/
|
||||
public class Deadlock {
|
||||
public static void main(String[] argv) {
|
||||
new Deadlock();
|
||||
|
||||
// Now find deadlock
|
||||
ThreadMonitor monitor = new ThreadMonitor();
|
||||
boolean found = false;
|
||||
while (!found) {
|
||||
found = monitor.findDeadlock();
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("\nPress <Enter> to exit this Deadlock program.\n");
|
||||
waitForEnterPressed();
|
||||
}
|
||||
|
||||
|
||||
private CyclicBarrier barrier = new CyclicBarrier(6);
|
||||
public Deadlock() {
|
||||
DeadlockThread[] dThreads = new DeadlockThread[6];
|
||||
|
||||
Monitor a = new Monitor("a");
|
||||
Monitor b = new Monitor("b");
|
||||
Monitor c = new Monitor("c");
|
||||
dThreads[0] = new DeadlockThread("MThread-1", a, b);
|
||||
dThreads[1] = new DeadlockThread("MThread-2", b, c);
|
||||
dThreads[2] = new DeadlockThread("MThread-3", c, a);
|
||||
|
||||
Lock d = new ReentrantLock();
|
||||
Lock e = new ReentrantLock();
|
||||
Lock f = new ReentrantLock();
|
||||
|
||||
dThreads[3] = new DeadlockThread("SThread-4", d, e);
|
||||
dThreads[4] = new DeadlockThread("SThread-5", e, f);
|
||||
dThreads[5] = new DeadlockThread("SThread-6", f, d);
|
||||
|
||||
// make them daemon threads so that the test will exit
|
||||
for (int i = 0; i < 6; i++) {
|
||||
dThreads[i].setDaemon(true);
|
||||
dThreads[i].start();
|
||||
}
|
||||
}
|
||||
|
||||
class DeadlockThread extends Thread {
|
||||
private Lock lock1 = null;
|
||||
private Lock lock2 = null;
|
||||
private Monitor mon1 = null;
|
||||
private Monitor mon2 = null;
|
||||
private boolean useSync;
|
||||
|
||||
DeadlockThread(String name, Lock lock1, Lock lock2) {
|
||||
super(name);
|
||||
this.lock1 = lock1;
|
||||
this.lock2 = lock2;
|
||||
this.useSync = true;
|
||||
}
|
||||
DeadlockThread(String name, Monitor mon1, Monitor mon2) {
|
||||
super(name);
|
||||
this.mon1 = mon1;
|
||||
this.mon2 = mon2;
|
||||
this.useSync = false;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
if (useSync) {
|
||||
syncLock();
|
||||
} else {
|
||||
monitorLock();
|
||||
}
|
||||
}
|
||||
private void syncLock() {
|
||||
lock1.lock();
|
||||
try {
|
||||
try {
|
||||
barrier.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} catch (BrokenBarrierException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
goSyncDeadlock();
|
||||
} finally {
|
||||
lock1.unlock();
|
||||
}
|
||||
}
|
||||
private void goSyncDeadlock() {
|
||||
try {
|
||||
barrier.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} catch (BrokenBarrierException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
lock2.lock();
|
||||
throw new RuntimeException("should not reach here.");
|
||||
}
|
||||
private void monitorLock() {
|
||||
synchronized (mon1) {
|
||||
try {
|
||||
barrier.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} catch (BrokenBarrierException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
goMonitorDeadlock();
|
||||
}
|
||||
}
|
||||
private void goMonitorDeadlock() {
|
||||
try {
|
||||
barrier.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} catch (BrokenBarrierException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
synchronized (mon2) {
|
||||
throw new RuntimeException(getName() + " should not reach here.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Monitor {
|
||||
String name;
|
||||
Monitor(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
private static void waitForEnterPressed() {
|
||||
try {
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
char ch = (char) System.in.read();
|
||||
if (ch<0||ch=='\n') {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
import javax.management.*;
|
||||
import javax.management.remote.*;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
/**
|
||||
* This FullThreadDump class demonstrates the capability to get
|
||||
* a full thread dump and also detect deadlock remotely.
|
||||
*/
|
||||
public class FullThreadDump {
|
||||
private MBeanServerConnection server;
|
||||
private JMXConnector jmxc;
|
||||
public FullThreadDump(String hostname, int port) {
|
||||
System.out.println("Connecting to " + hostname + ":" + port);
|
||||
|
||||
// Create an RMI connector client and connect it to
|
||||
// the RMI connector server
|
||||
String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
|
||||
connect(urlPath);
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
try {
|
||||
ThreadMonitor monitor = new ThreadMonitor(server);
|
||||
monitor.threadDump();
|
||||
if (!monitor.findDeadlock()) {
|
||||
System.out.println("No deadlock found.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("\nCommunication error: " + e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to a JMX agent of a given URL.
|
||||
*/
|
||||
private void connect(String urlPath) {
|
||||
try {
|
||||
JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
|
||||
this.jmxc = JMXConnectorFactory.connect(url);
|
||||
this.server = jmxc.getMBeanServerConnection();
|
||||
} catch (MalformedURLException e) {
|
||||
// should not reach here
|
||||
} catch (IOException e) {
|
||||
System.err.println("\nCommunication error: " + e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
String[] arg2 = args[0].split(":");
|
||||
if (arg2.length != 2) {
|
||||
usage();
|
||||
}
|
||||
String hostname = arg2[0];
|
||||
int port = -1;
|
||||
try {
|
||||
port = Integer.parseInt(arg2[1]);
|
||||
} catch (NumberFormatException x) {
|
||||
usage();
|
||||
}
|
||||
if (port < 0) {
|
||||
usage();
|
||||
}
|
||||
|
||||
// get full thread dump and perform deadlock detection
|
||||
FullThreadDump ftd = new FullThreadDump(hostname, port);
|
||||
ftd.dump();
|
||||
}
|
||||
|
||||
private static void usage() {
|
||||
System.out.println("Usage: java FullThreadDump <hostname>:<port>");
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
FullThreadDump demonstrates the use of the java.lang.management API
|
||||
to print the full thread dump. JDK 6 defines a new API to dump
|
||||
the information about monitors and java.util.concurrent ownable
|
||||
synchronizers.
|
||||
|
||||
This demo also illustrates how to monitor JDK 5 and JDK 6 VMs with
|
||||
two versions of APIs.
|
||||
|
||||
It contains two parts:
|
||||
a) Local monitoring within the application
|
||||
b) Remote monitoring by connecting to a JMX agent with a JMX service URL:
|
||||
service:jmx:rmi:///jndi/rmi://<hostName>:<portNum>/jmxrmi
|
||||
where <hostName> is the hostname and <portNum> is the port number
|
||||
to which the JMX agent will be connected.
|
||||
|
||||
To run the demo
|
||||
---------------
|
||||
a) Local Monitoring
|
||||
|
||||
java -cp <JDK_HOME>/demo/management/FullThreadDump/FullThreadDump.jar Deadlock
|
||||
|
||||
This will dump the stack trace and then detect deadlocks locally
|
||||
within the application.
|
||||
|
||||
b) Remote Monitoring
|
||||
|
||||
(1) Start the Deadlock application (or any other application)
|
||||
with the JMX agent as follows:
|
||||
|
||||
java -Dcom.sun.management.jmxremote.port=1090
|
||||
-Dcom.sun.management.jmxremote.ssl=false
|
||||
-Dcom.sun.management.jmxremote.authenticate=false
|
||||
-cp <JDK_HOME>/demo/management/FullThreadDump/FullThreadDump.jar
|
||||
Deadlock
|
||||
|
||||
This instruction uses the Sun's built-in support to enable a JMX agent.
|
||||
You can programmatically start a JMX agent with the RMI connector
|
||||
using javax.management.remote API. See the javadoc and examples for
|
||||
javax.management.remote API for details.
|
||||
|
||||
(2) Run FullThreadDump
|
||||
|
||||
java -jar <JDK_HOME>/demo/management/FullThreadDump/FullThreadDump.jar \
|
||||
localhost:1090
|
||||
|
||||
This will dump the stack trace and then print out the deadlocked threads.
|
||||
|
||||
These instructions assume that this installation's version of the java
|
||||
command is in your path. If it isn't, then you should either
|
||||
specify the complete path to the java command or update your
|
||||
PATH environment variable as described in the installation
|
||||
instructions for the Java(TM) SDK.
|
@ -1,266 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
import static java.lang.management.ManagementFactory.*;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.lang.management.ThreadInfo;
|
||||
import java.lang.management.LockInfo;
|
||||
import java.lang.management.MonitorInfo;
|
||||
import javax.management.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Example of using the java.lang.management API to dump stack trace
|
||||
* and to perform deadlock detection.
|
||||
*
|
||||
* @author Mandy Chung
|
||||
*/
|
||||
public class ThreadMonitor {
|
||||
private MBeanServerConnection server;
|
||||
private ThreadMXBean tmbean;
|
||||
private ObjectName objname;
|
||||
|
||||
// default - JDK 6+ VM
|
||||
private String findDeadlocksMethodName = "findDeadlockedThreads";
|
||||
private boolean canDumpLocks = true;
|
||||
|
||||
/**
|
||||
* Constructs a ThreadMonitor object to get thread information
|
||||
* in a remote JVM.
|
||||
*/
|
||||
public ThreadMonitor(MBeanServerConnection server) throws IOException {
|
||||
this.server = server;
|
||||
this.tmbean = newPlatformMXBeanProxy(server,
|
||||
THREAD_MXBEAN_NAME,
|
||||
ThreadMXBean.class);
|
||||
try {
|
||||
objname = new ObjectName(THREAD_MXBEAN_NAME);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
// should not reach here
|
||||
InternalError ie = new InternalError(e.getMessage());
|
||||
ie.initCause(e);
|
||||
throw ie;
|
||||
}
|
||||
parseMBeanInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ThreadMonitor object to get thread information
|
||||
* in the local JVM.
|
||||
*/
|
||||
public ThreadMonitor() {
|
||||
this.tmbean = getThreadMXBean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the thread dump information to System.out.
|
||||
*/
|
||||
public void threadDump() {
|
||||
if (canDumpLocks) {
|
||||
if (tmbean.isObjectMonitorUsageSupported() &&
|
||||
tmbean.isSynchronizerUsageSupported()) {
|
||||
// Print lock info if both object monitor usage
|
||||
// and synchronizer usage are supported.
|
||||
// This sample code can be modified to handle if
|
||||
// either monitor usage or synchronizer usage is supported.
|
||||
dumpThreadInfoWithLocks();
|
||||
}
|
||||
} else {
|
||||
dumpThreadInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private void dumpThreadInfo() {
|
||||
System.out.println("Full Java thread dump");
|
||||
long[] tids = tmbean.getAllThreadIds();
|
||||
ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
|
||||
for (ThreadInfo ti : tinfos) {
|
||||
printThreadInfo(ti);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the thread dump information with locks info to System.out.
|
||||
*/
|
||||
private void dumpThreadInfoWithLocks() {
|
||||
System.out.println("Full Java thread dump with locks info");
|
||||
|
||||
ThreadInfo[] tinfos = tmbean.dumpAllThreads(true, true);
|
||||
for (ThreadInfo ti : tinfos) {
|
||||
printThreadInfo(ti);
|
||||
LockInfo[] syncs = ti.getLockedSynchronizers();
|
||||
printLockInfo(syncs);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private static String INDENT = " ";
|
||||
|
||||
private void printThreadInfo(ThreadInfo ti) {
|
||||
// print thread information
|
||||
printThread(ti);
|
||||
|
||||
// print stack trace with locks
|
||||
StackTraceElement[] stacktrace = ti.getStackTrace();
|
||||
MonitorInfo[] monitors = ti.getLockedMonitors();
|
||||
for (int i = 0; i < stacktrace.length; i++) {
|
||||
StackTraceElement ste = stacktrace[i];
|
||||
System.out.println(INDENT + "at " + ste.toString());
|
||||
for (MonitorInfo mi : monitors) {
|
||||
if (mi.getLockedStackDepth() == i) {
|
||||
System.out.println(INDENT + " - locked " + mi);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private void printThread(ThreadInfo ti) {
|
||||
StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\"" +
|
||||
" Id=" + ti.getThreadId() +
|
||||
" in " + ti.getThreadState());
|
||||
if (ti.getLockName() != null) {
|
||||
sb.append(" on lock=" + ti.getLockName());
|
||||
}
|
||||
if (ti.isSuspended()) {
|
||||
sb.append(" (suspended)");
|
||||
}
|
||||
if (ti.isInNative()) {
|
||||
sb.append(" (running in native)");
|
||||
}
|
||||
System.out.println(sb.toString());
|
||||
if (ti.getLockOwnerName() != null) {
|
||||
System.out.println(INDENT + " owned by " + ti.getLockOwnerName() +
|
||||
" Id=" + ti.getLockOwnerId());
|
||||
}
|
||||
}
|
||||
|
||||
private void printMonitorInfo(ThreadInfo ti) {
|
||||
MonitorInfo[] monitors = ti.getLockedMonitors();
|
||||
System.out.println(INDENT + "Locked monitors: count = " + monitors.length);
|
||||
for (MonitorInfo mi : monitors) {
|
||||
System.out.println(INDENT + " - " + mi + " locked at ");
|
||||
System.out.println(INDENT + " " + mi.getLockedStackDepth() +
|
||||
" " + mi.getLockedStackFrame());
|
||||
}
|
||||
}
|
||||
|
||||
private void printLockInfo(LockInfo[] locks) {
|
||||
System.out.println(INDENT + "Locked synchronizers: count = " + locks.length);
|
||||
for (LockInfo li : locks) {
|
||||
System.out.println(INDENT + " - " + li);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any threads are deadlocked. If any, print
|
||||
* the thread dump information.
|
||||
*/
|
||||
public boolean findDeadlock() {
|
||||
long[] tids;
|
||||
if (findDeadlocksMethodName.equals("findDeadlockedThreads") &&
|
||||
tmbean.isSynchronizerUsageSupported()) {
|
||||
tids = tmbean.findDeadlockedThreads();
|
||||
if (tids == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
System.out.println("Deadlock found :-");
|
||||
ThreadInfo[] infos = tmbean.getThreadInfo(tids, true, true);
|
||||
for (ThreadInfo ti : infos) {
|
||||
printThreadInfo(ti);
|
||||
printMonitorInfo(ti);
|
||||
printLockInfo(ti.getLockedSynchronizers());
|
||||
System.out.println();
|
||||
}
|
||||
} else {
|
||||
tids = tmbean.findMonitorDeadlockedThreads();
|
||||
if (tids == null) {
|
||||
return false;
|
||||
}
|
||||
ThreadInfo[] infos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
|
||||
for (ThreadInfo ti : infos) {
|
||||
// print thread information
|
||||
printThreadInfo(ti);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void parseMBeanInfo() throws IOException {
|
||||
try {
|
||||
MBeanOperationInfo[] mopis = server.getMBeanInfo(objname).getOperations();
|
||||
|
||||
// look for findDeadlockedThreads operations;
|
||||
boolean found = false;
|
||||
for (MBeanOperationInfo op : mopis) {
|
||||
if (op.getName().equals(findDeadlocksMethodName)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// if findDeadlockedThreads operation doesn't exist,
|
||||
// the target VM is running on JDK 5 and details about
|
||||
// synchronizers and locks cannot be dumped.
|
||||
findDeadlocksMethodName = "findMonitorDeadlockedThreads";
|
||||
canDumpLocks = false;
|
||||
}
|
||||
} catch (IntrospectionException e) {
|
||||
InternalError ie = new InternalError(e.getMessage());
|
||||
ie.initCause(e);
|
||||
throw ie;
|
||||
} catch (InstanceNotFoundException e) {
|
||||
InternalError ie = new InternalError(e.getMessage());
|
||||
ie.initCause(e);
|
||||
throw ie;
|
||||
} catch (ReflectionException e) {
|
||||
InternalError ie = new InternalError(e.getMessage());
|
||||
ie.initCause(e);
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,427 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Example of using the java.lang.management API to sort threads
|
||||
* by CPU usage.
|
||||
*
|
||||
* JTop class can be run as a standalone application.
|
||||
* It first establishs a connection to a target VM specified
|
||||
* by the given hostname and port number where the JMX agent
|
||||
* to be connected. It then polls for the thread information
|
||||
* and the CPU consumption of each thread to display every 2
|
||||
* seconds.
|
||||
*
|
||||
* It is also used by JTopPlugin which is a JConsolePlugin
|
||||
* that can be used with JConsole (see README.txt). The JTop
|
||||
* GUI will be added as a JConsole tab by the JTop plugin.
|
||||
*
|
||||
* @see com.sun.tools.jconsole.JConsolePlugin
|
||||
*
|
||||
* @author Mandy Chung
|
||||
*/
|
||||
import java.lang.management.*;
|
||||
import javax.management.*;
|
||||
import javax.management.remote.*;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.text.NumberFormat;
|
||||
import java.net.MalformedURLException;
|
||||
import static java.lang.management.ManagementFactory.*;
|
||||
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
/**
|
||||
* JTop is a JPanel to display thread's name, CPU time, and its state
|
||||
* in a table.
|
||||
*/
|
||||
public class JTop extends JPanel {
|
||||
|
||||
private static class StatusBar extends JPanel {
|
||||
private static final long serialVersionUID = -6483392381797633018L;
|
||||
private final JLabel statusText;
|
||||
|
||||
public StatusBar(boolean defaultVisible) {
|
||||
super(new GridLayout(1, 1));
|
||||
statusText = new JLabel();
|
||||
statusText.setVisible(defaultVisible);
|
||||
add(statusText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMaximumSize() {
|
||||
Dimension maximum = super.getMaximumSize();
|
||||
Dimension minimum = getMinimumSize();
|
||||
return new Dimension(maximum.width, minimum.height);
|
||||
}
|
||||
|
||||
public void setMessage(String text) {
|
||||
statusText.setText(text);
|
||||
statusText.setVisible(true);
|
||||
}
|
||||
}
|
||||
private static final long serialVersionUID = -1499762160973870696L;
|
||||
private MBeanServerConnection server;
|
||||
private ThreadMXBean tmbean;
|
||||
private MyTableModel tmodel;
|
||||
private final StatusBar statusBar;
|
||||
public JTop() {
|
||||
super(new GridBagLayout());
|
||||
|
||||
tmodel = new MyTableModel();
|
||||
JTable table = new JTable(tmodel);
|
||||
table.setPreferredScrollableViewportSize(new Dimension(500, 300));
|
||||
|
||||
// Set the renderer to format Double
|
||||
table.setDefaultRenderer(Double.class, new DoubleRenderer());
|
||||
// Add some space
|
||||
table.setIntercellSpacing(new Dimension(6,3));
|
||||
table.setRowHeight(table.getRowHeight() + 4);
|
||||
|
||||
// Create the scroll pane and add the table to it.
|
||||
JScrollPane scrollPane = new JScrollPane(table);
|
||||
|
||||
// Add the scroll pane to this panel.
|
||||
GridBagConstraints c1 = new GridBagConstraints();
|
||||
c1.fill = GridBagConstraints.BOTH;
|
||||
c1.gridy = 0;
|
||||
c1.gridx = 0;
|
||||
c1.weightx = 1;
|
||||
c1.weighty = 1;
|
||||
add(scrollPane, c1);
|
||||
|
||||
statusBar = new StatusBar(false);
|
||||
GridBagConstraints c2 = new GridBagConstraints();
|
||||
c2.fill = GridBagConstraints.HORIZONTAL;
|
||||
c2.gridy = 1;
|
||||
c2.gridx = 0;
|
||||
c2.weightx = 1.0;
|
||||
c2.weighty = 0.0;
|
||||
add(statusBar, c2);
|
||||
}
|
||||
|
||||
// Set the MBeanServerConnection object for communicating
|
||||
// with the target VM
|
||||
public void setMBeanServerConnection(MBeanServerConnection mbs) {
|
||||
this.server = mbs;
|
||||
try {
|
||||
this.tmbean = newPlatformMXBeanProxy(server,
|
||||
THREAD_MXBEAN_NAME,
|
||||
ThreadMXBean.class);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!tmbean.isThreadCpuTimeSupported()) {
|
||||
statusBar.setMessage("Monitored VM does not support thread CPU time measurement");
|
||||
} else {
|
||||
try {
|
||||
tmbean.setThreadCpuTimeEnabled(true);
|
||||
} catch (SecurityException e) {
|
||||
statusBar.setMessage("Monitored VM does not have permission for enabling thread cpu time measurement");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyTableModel extends AbstractTableModel {
|
||||
private static final long serialVersionUID = -7877310288576779514L;
|
||||
private String[] columnNames = {"ThreadName",
|
||||
"CPU(sec)",
|
||||
"State"};
|
||||
// List of all threads. The key of each entry is the CPU time
|
||||
// and its value is the ThreadInfo object with no stack trace.
|
||||
private List<Map.Entry<Long, ThreadInfo>> threadList =
|
||||
Collections.emptyList();
|
||||
|
||||
public MyTableModel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return columnNames.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return threadList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int col) {
|
||||
return columnNames[col];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int col) {
|
||||
Map.Entry<Long, ThreadInfo> me = threadList.get(row);
|
||||
switch (col) {
|
||||
case 0 :
|
||||
// Column 0 shows the thread name
|
||||
return me.getValue().getThreadName();
|
||||
case 1 :
|
||||
// Column 1 shows the CPU usage
|
||||
long ns = me.getKey().longValue();
|
||||
double sec = ns / 1000000000;
|
||||
return new Double(sec);
|
||||
case 2 :
|
||||
// Column 2 shows the thread state
|
||||
return me.getValue().getThreadState();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int c) {
|
||||
return getValueAt(0, c).getClass();
|
||||
}
|
||||
|
||||
void setThreadList(List<Map.Entry<Long, ThreadInfo>> list) {
|
||||
threadList = list;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the thread list with CPU consumption and the ThreadInfo
|
||||
* for each thread sorted by the CPU time.
|
||||
*/
|
||||
private List<Map.Entry<Long, ThreadInfo>> getThreadList() {
|
||||
// Get all threads and their ThreadInfo objects
|
||||
// with no stack trace
|
||||
long[] tids = tmbean.getAllThreadIds();
|
||||
ThreadInfo[] tinfos = tmbean.getThreadInfo(tids);
|
||||
|
||||
// build a map with key = CPU time and value = ThreadInfo
|
||||
SortedMap<Long, ThreadInfo> map = new TreeMap<Long, ThreadInfo>();
|
||||
for (int i = 0; i < tids.length; i++) {
|
||||
long cpuTime = tmbean.getThreadCpuTime(tids[i]);
|
||||
// filter out threads that have been terminated
|
||||
if (cpuTime != -1 && tinfos[i] != null) {
|
||||
map.put(new Long(cpuTime), tinfos[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// build the thread list and sort it with CPU time
|
||||
// in decreasing order
|
||||
Set<Map.Entry<Long, ThreadInfo>> set = map.entrySet();
|
||||
List<Map.Entry<Long, ThreadInfo>> list =
|
||||
new ArrayList<Map.Entry<Long, ThreadInfo>>(set);
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format Double with 4 fraction digits
|
||||
*/
|
||||
class DoubleRenderer extends DefaultTableCellRenderer {
|
||||
private static final long serialVersionUID = 1704639497162584382L;
|
||||
NumberFormat formatter;
|
||||
public DoubleRenderer() {
|
||||
super();
|
||||
setHorizontalAlignment(JLabel.RIGHT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
if (formatter==null) {
|
||||
formatter = NumberFormat.getInstance();
|
||||
formatter.setMinimumFractionDigits(4);
|
||||
}
|
||||
setText((value == null) ? "" : formatter.format(value));
|
||||
}
|
||||
}
|
||||
|
||||
// SwingWorker responsible for updating the GUI
|
||||
//
|
||||
// It first gets the thread and CPU usage information as a
|
||||
// background task done by a worker thread so that
|
||||
// it will not block the event dispatcher thread.
|
||||
//
|
||||
// When the worker thread finishes, the event dispatcher
|
||||
// thread will invoke the done() method which will update
|
||||
// the UI.
|
||||
class Worker extends SwingWorker<List<Map.Entry<Long, ThreadInfo>>,Object> {
|
||||
private MyTableModel tmodel;
|
||||
Worker(MyTableModel tmodel) {
|
||||
this.tmodel = tmodel;
|
||||
}
|
||||
|
||||
// Get the current thread info and CPU time
|
||||
@Override
|
||||
public List<Map.Entry<Long, ThreadInfo>> doInBackground() {
|
||||
return getThreadList();
|
||||
}
|
||||
|
||||
// fire table data changed to trigger GUI update
|
||||
// when doInBackground() is finished
|
||||
@Override
|
||||
protected void done() {
|
||||
try {
|
||||
// Set table model with the new thread list
|
||||
tmodel.setThreadList(get());
|
||||
// refresh the table model
|
||||
tmodel.fireTableDataChanged();
|
||||
} catch (InterruptedException e) {
|
||||
} catch (ExecutionException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return a new SwingWorker for UI update
|
||||
public SwingWorker<?,?> newSwingWorker() {
|
||||
return new Worker(tmodel);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Validate the input arguments
|
||||
if (args.length != 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
String[] arg2 = args[0].split(":");
|
||||
if (arg2.length != 2) {
|
||||
usage();
|
||||
}
|
||||
String hostname = arg2[0];
|
||||
int port = -1;
|
||||
try {
|
||||
port = Integer.parseInt(arg2[1]);
|
||||
} catch (NumberFormatException x) {
|
||||
usage();
|
||||
}
|
||||
if (port < 0) {
|
||||
usage();
|
||||
}
|
||||
|
||||
// Create the JTop Panel
|
||||
final JTop jtop = new JTop();
|
||||
// Set up the MBeanServerConnection to the target VM
|
||||
MBeanServerConnection server = connect(hostname, port);
|
||||
jtop.setMBeanServerConnection(server);
|
||||
|
||||
// A timer task to update GUI per each interval
|
||||
TimerTask timerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Schedule the SwingWorker to update the GUI
|
||||
jtop.newSwingWorker().execute();
|
||||
}
|
||||
};
|
||||
|
||||
// Create the standalone window with JTop panel
|
||||
// by the event dispatcher thread
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
createAndShowGUI(jtop);
|
||||
}
|
||||
});
|
||||
|
||||
// refresh every 2 seconds
|
||||
Timer timer = new Timer("JTop Sampling thread");
|
||||
timer.schedule(timerTask, 0, 2000);
|
||||
|
||||
}
|
||||
|
||||
// Establish a connection with the remote application
|
||||
//
|
||||
// You can modify the urlPath to the address of the JMX agent
|
||||
// of your application if it has a different URL.
|
||||
//
|
||||
// You can also modify the following code to take
|
||||
// username and password for client authentication.
|
||||
private static MBeanServerConnection connect(String hostname, int port) {
|
||||
// Create an RMI connector client and connect it to
|
||||
// the RMI connector server
|
||||
String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
|
||||
MBeanServerConnection server = null;
|
||||
try {
|
||||
JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
|
||||
JMXConnector jmxc = JMXConnectorFactory.connect(url);
|
||||
server = jmxc.getMBeanServerConnection();
|
||||
} catch (MalformedURLException e) {
|
||||
// should not reach here
|
||||
} catch (IOException e) {
|
||||
System.err.println("\nCommunication error: " + e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
private static void usage() {
|
||||
System.out.println("Usage: java JTop <hostname>:<port>");
|
||||
System.exit(1);
|
||||
}
|
||||
/**
|
||||
* Create the GUI and show it. For thread safety,
|
||||
* this method should be invoked from the
|
||||
* event-dispatching thread.
|
||||
*/
|
||||
private static void createAndShowGUI(JPanel jtop) {
|
||||
// Create and set up the window.
|
||||
JFrame frame = new JFrame("JTop");
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||
|
||||
// Create and set up the content pane.
|
||||
JComponent contentPane = (JComponent) frame.getContentPane();
|
||||
contentPane.add(jtop, BorderLayout.CENTER);
|
||||
contentPane.setOpaque(true); //content panes must be opaque
|
||||
contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
|
||||
frame.setContentPane(contentPane);
|
||||
|
||||
// Display the window.
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Example of a JConsole Plugin. This loads JTop as a JConsole tab.
|
||||
*
|
||||
* @author Mandy Chung
|
||||
*/
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import com.sun.tools.jconsole.JConsoleContext;
|
||||
import com.sun.tools.jconsole.JConsoleContext.ConnectionState;
|
||||
import com.sun.tools.jconsole.JConsolePlugin;
|
||||
|
||||
/**
|
||||
* JTopPlugin is a subclass to com.sun.tools.jconsole.JConsolePlugin
|
||||
*
|
||||
* JTopPlugin is loaded and instantiated by JConsole. One instance
|
||||
* is created for each window that JConsole creates. It listens to
|
||||
* the connected property change so that it will update JTop with
|
||||
* the valid MBeanServerConnection object. JTop is a JPanel object
|
||||
* displaying the thread and its CPU usage information.
|
||||
*/
|
||||
public class JTopPlugin extends JConsolePlugin implements PropertyChangeListener
|
||||
{
|
||||
private JTop jtop = null;
|
||||
private Map<String, JPanel> tabs = null;
|
||||
|
||||
public JTopPlugin() {
|
||||
// register itself as a listener
|
||||
addContextPropertyChangeListener(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a JTop tab to be added in JConsole.
|
||||
*/
|
||||
@Override
|
||||
public synchronized Map<String, JPanel> getTabs() {
|
||||
if (tabs == null) {
|
||||
jtop = new JTop();
|
||||
jtop.setMBeanServerConnection(
|
||||
getContext().getMBeanServerConnection());
|
||||
// use LinkedHashMap if you want a predictable order
|
||||
// of the tabs to be added in JConsole
|
||||
tabs = new LinkedHashMap<String, JPanel>();
|
||||
tabs.put("JTop", jtop);
|
||||
}
|
||||
return tabs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a SwingWorker which is responsible for updating the JTop tab.
|
||||
*/
|
||||
@Override
|
||||
public SwingWorker<?,?> newSwingWorker() {
|
||||
return jtop.newSwingWorker();
|
||||
}
|
||||
|
||||
// You can implement the dispose() method if you need to release
|
||||
// any resource when the plugin instance is disposed when the JConsole
|
||||
// window is closed.
|
||||
//
|
||||
// public void dispose() {
|
||||
// }
|
||||
|
||||
/*
|
||||
* Property listener to reset the MBeanServerConnection
|
||||
* at reconnection time.
|
||||
*/
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent ev) {
|
||||
String prop = ev.getPropertyName();
|
||||
if (prop == JConsoleContext.CONNECTION_STATE_PROPERTY) {
|
||||
ConnectionState newState = (ConnectionState)ev.getNewValue();
|
||||
// JConsole supports disconnection and reconnection
|
||||
// The MBeanServerConnection will become invalid when
|
||||
// disconnected. Need to use the new MBeanServerConnection object
|
||||
// created at reconnection time.
|
||||
if (newState == ConnectionState.CONNECTED && jtop != null) {
|
||||
jtop.setMBeanServerConnection(
|
||||
getContext().getMBeanServerConnection());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
JTopPlugin
|
@ -1,61 +0,0 @@
|
||||
JTop monitors the CPU usage of all threads in a remote application
|
||||
which has remote management enabled. JTop demonstrates the use of
|
||||
the java.lang.management API to obtain the CPU consumption for
|
||||
each thread.
|
||||
|
||||
JTop is also a JConsole Plugin. See below for details.
|
||||
|
||||
JTop Standalone GUI
|
||||
===================
|
||||
|
||||
JTop first establishes a connection to a JMX agent in a remote
|
||||
application with a JMX service URL:
|
||||
service:jmx:rmi:///jndi/rmi://<hostName>:<portNum>/jmxrmi
|
||||
|
||||
where <hostName> is the hostname and <portNum> is the port number
|
||||
to which the JMX agent will be connected.
|
||||
|
||||
To run the demo
|
||||
---------------
|
||||
(1) Start the application with the JMX agent - here's an example of
|
||||
how the Java2D is started
|
||||
|
||||
java -Dcom.sun.management.jmxremote.port=1090
|
||||
-Dcom.sun.management.jmxremote.ssl=false
|
||||
-Dcom.sun.management.jmxremote.authenticate=false
|
||||
-jar <JDK_HOME>/demo/jfc/Java2D/Java2Demo.jar
|
||||
|
||||
This instruction uses the Sun's built-in support to enable a JMX agent
|
||||
with a JMX service URL as described above.
|
||||
You can programmatically start a JMX agent with the RMI connector
|
||||
using javax.management.remote API. See the javadoc and examples for
|
||||
javax.management.remote API for details.
|
||||
|
||||
(2) Run JTop on a different machine:
|
||||
|
||||
java -jar <JDK_HOME>/demo/management/JTop/JTop.jar <hostname>:1090
|
||||
|
||||
where <hostname> is where the Java2Demo.jar runs in step (1).
|
||||
|
||||
These instructions assume that this installation's version of the java
|
||||
command is in your path. If it isn't, then you should either
|
||||
specify the complete path to the java command or update your
|
||||
PATH environment variable as described in the installation
|
||||
instructions for the Java(TM) SDK.
|
||||
|
||||
JTop JConsole Plugin
|
||||
====================
|
||||
|
||||
JTop is a JConsole Plugin which adds a "JTop" tab to JConsole.
|
||||
|
||||
To run JConsole with the JTop plugin
|
||||
------------------------------------
|
||||
jconsole -pluginpath <JDK_HOME>/demo/management/JTop/JTop.jar
|
||||
|
||||
|
||||
To compile
|
||||
----------
|
||||
javac -classpath <JDK_HOME>/lib/jconsole.jar JTopPlugin.java
|
||||
|
||||
com.sun.tools.jconsole API is in jconsole.jar which is needed
|
||||
in the classpath for compilation.
|
@ -1,491 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Date;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EtchedBorder;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import java.lang.management.*;
|
||||
/**
|
||||
* Demo code which plots the memory usage by all memory pools.
|
||||
* The memory usage is sampled at some time interval using
|
||||
* java.lang.management API. This demo code is modified based
|
||||
* java2d MemoryMonitor demo.
|
||||
*/
|
||||
public class MemoryMonitor extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = -3463003810776195761L;
|
||||
static JCheckBox dateStampCB = new JCheckBox("Output Date Stamp");
|
||||
public Surface surf;
|
||||
JPanel controls;
|
||||
boolean doControls;
|
||||
JTextField tf;
|
||||
// Get memory pools.
|
||||
static java.util.List<MemoryPoolMXBean> mpools =
|
||||
ManagementFactory.getMemoryPoolMXBeans();
|
||||
// Total number of memory pools.
|
||||
static int numPools = mpools.size();
|
||||
|
||||
public MemoryMonitor() {
|
||||
setLayout(new BorderLayout());
|
||||
setBorder(new TitledBorder(new EtchedBorder(), "Memory Monitor"));
|
||||
add(surf = new Surface());
|
||||
controls = new JPanel();
|
||||
controls.setPreferredSize(new Dimension(135,80));
|
||||
Font font = new Font("serif", Font.PLAIN, 10);
|
||||
JLabel label = new JLabel("Sample Rate");
|
||||
label.setFont(font);
|
||||
label.setForeground(Color.red);
|
||||
controls.add(label);
|
||||
tf = new JTextField("1000");
|
||||
tf.setPreferredSize(new Dimension(45,20));
|
||||
controls.add(tf);
|
||||
controls.add(label = new JLabel("ms"));
|
||||
label.setFont(font);
|
||||
label.setForeground(Color.red);
|
||||
controls.add(dateStampCB);
|
||||
dateStampCB.setFont(font);
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
removeAll();
|
||||
if ((doControls = !doControls)) {
|
||||
surf.stop();
|
||||
add(controls);
|
||||
} else {
|
||||
try {
|
||||
surf.sleepAmount = Long.parseLong(tf.getText().trim());
|
||||
} catch (Exception ex) {}
|
||||
surf.start();
|
||||
add(surf);
|
||||
}
|
||||
validate();
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public class Surface extends JPanel implements Runnable {
|
||||
|
||||
public Thread thread;
|
||||
public long sleepAmount = 1000;
|
||||
public int usageHistCount = 20000;
|
||||
private int w, h;
|
||||
private BufferedImage bimg;
|
||||
private Graphics2D big;
|
||||
private Font font = new Font("Times New Roman", Font.PLAIN, 11);
|
||||
private int columnInc;
|
||||
private float usedMem[][];
|
||||
private float usedMemMax[]; // Used when max pool size is undefined
|
||||
private int ptNum[];
|
||||
private int ascent, descent;
|
||||
private Rectangle graphOutlineRect = new Rectangle();
|
||||
private Rectangle2D mfRect = new Rectangle2D.Float();
|
||||
private Rectangle2D muRect = new Rectangle2D.Float();
|
||||
private Line2D graphLine = new Line2D.Float();
|
||||
private Color graphColor = new Color(46, 139, 87);
|
||||
private Color mfColor = new Color(0, 100, 0);
|
||||
private String usedStr;
|
||||
|
||||
|
||||
public Surface() {
|
||||
setBackground(Color.black);
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (thread == null) start(); else stop();
|
||||
}
|
||||
});
|
||||
usedMem = new float[numPools][];
|
||||
usedMemMax = new float[numPools];
|
||||
for (int i = 0; i < numPools; i++) {
|
||||
usedMemMax[i] = 1024f * 1024f ;
|
||||
}
|
||||
ptNum = new int[numPools];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMaximumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(135,80);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
|
||||
if (big == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
big.setBackground(getBackground());
|
||||
big.clearRect(0,0,w,h);
|
||||
|
||||
|
||||
h = h / ((numPools + numPools%2) / 2);
|
||||
w = w / 2;
|
||||
|
||||
int k=0; // index of memory pool.
|
||||
for (int i=0; i < 2;i++) {
|
||||
for (int j=0; j < (numPools + numPools%2)/ 2; j++) {
|
||||
plotMemoryUsage(w*i,h*j,w,h,k);
|
||||
if (++k >= numPools) {
|
||||
i = 3;
|
||||
j = (numPools + numPools%2)/ 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
g.drawImage(bimg, 0, 0, this);
|
||||
}
|
||||
|
||||
public void plotMemoryUsage(int x1, int y1, int x2, int y2, int npool) {
|
||||
|
||||
MemoryPoolMXBean mp = mpools.get(npool);
|
||||
float usedMemory = mp.getUsage().getUsed();
|
||||
float totalMemory = mp.getUsage().getMax();
|
||||
if (totalMemory < 0) { // Max is undefined for this pool
|
||||
if (usedMemory > usedMemMax[npool]) {
|
||||
usedMemMax[npool] = usedMemory;
|
||||
}
|
||||
totalMemory = usedMemMax[npool];
|
||||
}
|
||||
|
||||
// .. Draw allocated and used strings ..
|
||||
big.setColor(Color.green);
|
||||
|
||||
// Print Max memory allocated for this memory pool.
|
||||
big.drawString(String.valueOf((int)totalMemory/1024) + "K Max ", x1+4.0f, (float) y1 + ascent+0.5f);
|
||||
big.setColor(Color.yellow);
|
||||
|
||||
// Print the memory pool name.
|
||||
big.drawString(mp.getName(), x1+x2/2, (float) y1 + ascent+0.5f);
|
||||
|
||||
// Print the memory used by this memory pool.
|
||||
usedStr = String.valueOf((int)usedMemory/1024)
|
||||
+ "K used";
|
||||
big.setColor(Color.green);
|
||||
big.drawString(usedStr, x1+4, y1+y2-descent);
|
||||
|
||||
// Calculate remaining size
|
||||
float ssH = ascent + descent;
|
||||
float remainingHeight = y2 - (ssH*2) - 0.5f;
|
||||
float blockHeight = remainingHeight/10;
|
||||
float blockWidth = 20.0f;
|
||||
float remainingWidth = x2 - blockWidth - 10;
|
||||
|
||||
// .. Memory Free ..
|
||||
big.setColor(mfColor);
|
||||
int MemUsage = (int) (((totalMemory - usedMemory) / totalMemory) * 10);
|
||||
int i = 0;
|
||||
for ( ; i < MemUsage ; i++) {
|
||||
mfRect.setRect(x1+5,(float) y1+ssH+i*blockHeight,
|
||||
blockWidth, blockHeight-1);
|
||||
big.fill(mfRect);
|
||||
}
|
||||
|
||||
// .. Memory Used ..
|
||||
big.setColor(Color.green);
|
||||
for ( ; i < 10; i++) {
|
||||
muRect.setRect(x1+5,(float) y1 + ssH+i*blockHeight,
|
||||
blockWidth, blockHeight-1);
|
||||
big.fill(muRect);
|
||||
}
|
||||
|
||||
// .. Draw History Graph ..
|
||||
if (remainingWidth <= 30) remainingWidth = (float)30;
|
||||
if (remainingHeight <= ssH) remainingHeight = ssH;
|
||||
big.setColor(graphColor);
|
||||
int graphX = x1+30;
|
||||
int graphY = y1 + (int) ssH;
|
||||
int graphW = (int) remainingWidth;
|
||||
int graphH = (int) remainingHeight;
|
||||
|
||||
graphOutlineRect.setRect(graphX, graphY, graphW, graphH);
|
||||
big.draw(graphOutlineRect);
|
||||
|
||||
int graphRow = graphH/10;
|
||||
|
||||
// .. Draw row ..
|
||||
for (int j = graphY; j <= graphH+graphY; j += graphRow) {
|
||||
graphLine.setLine(graphX,j,graphX+graphW,j);
|
||||
big.draw(graphLine);
|
||||
}
|
||||
|
||||
// .. Draw animated column movement ..
|
||||
int graphColumn = graphW/15;
|
||||
|
||||
if (columnInc == 0) {
|
||||
columnInc = graphColumn;
|
||||
}
|
||||
|
||||
for (int j = graphX+columnInc; j < graphW+graphX; j+=graphColumn) {
|
||||
graphLine.setLine(j,graphY,j,graphY+graphH);
|
||||
big.draw(graphLine);
|
||||
}
|
||||
|
||||
--columnInc;
|
||||
|
||||
// Plot memory usage by this memory pool.
|
||||
if (usedMem[npool] == null) {
|
||||
usedMem[npool] = new float[usageHistCount];
|
||||
ptNum[npool] = 0;
|
||||
}
|
||||
|
||||
// save memory usage history.
|
||||
usedMem[npool][ptNum[npool]] = usedMemory;
|
||||
|
||||
big.setColor(Color.yellow);
|
||||
|
||||
int w1; // width of memory usage history.
|
||||
if (ptNum[npool] > graphW) {
|
||||
w1 = graphW;
|
||||
} else {
|
||||
w1 = ptNum[npool];
|
||||
}
|
||||
|
||||
|
||||
for (int j=graphX+graphW-w1, k=ptNum[npool]-w1; k < ptNum[npool];
|
||||
k++, j++) {
|
||||
if (k != 0) {
|
||||
if (usedMem[npool][k] != usedMem[npool][k-1]) {
|
||||
int h1 = (int)(graphY + graphH * ((totalMemory -usedMem[npool][k-1])/totalMemory));
|
||||
int h2 = (int)(graphY + graphH * ((totalMemory -usedMem[npool][k])/totalMemory));
|
||||
big.drawLine(j-1, h1, j, h2);
|
||||
} else {
|
||||
int h1 = (int)(graphY + graphH * ((totalMemory -usedMem[npool][k])/totalMemory));
|
||||
big.fillRect(j, h1, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ptNum[npool]+2 == usedMem[npool].length) {
|
||||
// throw out oldest point
|
||||
for (int j = 1;j < ptNum[npool]; j++) {
|
||||
usedMem[npool][j-1] = usedMem[npool][j];
|
||||
}
|
||||
--ptNum[npool];
|
||||
} else {
|
||||
ptNum[npool]++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void start() {
|
||||
thread = new Thread(this);
|
||||
thread.setPriority(Thread.MIN_PRIORITY);
|
||||
thread.setName("MemoryMonitor");
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
public synchronized void stop() {
|
||||
thread = null;
|
||||
notify();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
Thread me = Thread.currentThread();
|
||||
|
||||
while (thread == me && !isShowing() || getSize().width == 0) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) { return; }
|
||||
}
|
||||
|
||||
while (thread == me && isShowing()) {
|
||||
Dimension d = getSize();
|
||||
if (d.width != w || d.height != h) {
|
||||
w = d.width;
|
||||
h = d.height;
|
||||
bimg = (BufferedImage) createImage(w, h);
|
||||
big = bimg.createGraphics();
|
||||
big.setFont(font);
|
||||
FontMetrics fm = big.getFontMetrics(font);
|
||||
ascent = fm.getAscent();
|
||||
descent = fm.getDescent();
|
||||
}
|
||||
repaint();
|
||||
try {
|
||||
Thread.sleep(sleepAmount);
|
||||
} catch (InterruptedException e) { break; }
|
||||
if (MemoryMonitor.dateStampCB.isSelected()) {
|
||||
System.out.println(new Date().toString() + " " + usedStr);
|
||||
}
|
||||
}
|
||||
thread = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test thread to consume memory
|
||||
static class Memeater extends ClassLoader implements Runnable {
|
||||
Object y[];
|
||||
public Memeater() {}
|
||||
@Override
|
||||
public void run() {
|
||||
y = new Object[10000000];
|
||||
int k =0;
|
||||
while(true) {
|
||||
if (k == 5000000) k=0;
|
||||
y[k++] = new Object();
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (Exception x){}
|
||||
|
||||
// to consume perm gen storage
|
||||
try {
|
||||
// the classes are small so we load 10 at a time
|
||||
for (int i=0; i<10; i++) {
|
||||
loadNext();
|
||||
}
|
||||
} catch (ClassNotFoundException x) {
|
||||
// ignore exception
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Class<?> loadNext() throws ClassNotFoundException {
|
||||
|
||||
// public class TestNNNNNN extends java.lang.Object{
|
||||
// public TestNNNNNN();
|
||||
// Code:
|
||||
// 0: aload_0
|
||||
// 1: invokespecial #1; //Method java/lang/Object."<init>":()V
|
||||
// 4: return
|
||||
// }
|
||||
|
||||
int begin[] = {
|
||||
0xca, 0xfe, 0xba, 0xbe, 0x00, 0x00, 0x00, 0x30,
|
||||
0x00, 0x0a, 0x0a, 0x00, 0x03, 0x00, 0x07, 0x07,
|
||||
0x00, 0x08, 0x07, 0x00, 0x09, 0x01, 0x00, 0x06,
|
||||
0x3c, 0x69, 0x6e, 0x69, 0x74, 0x3e, 0x01, 0x00,
|
||||
0x03, 0x28, 0x29, 0x56, 0x01, 0x00, 0x04, 0x43,
|
||||
0x6f, 0x64, 0x65, 0x0c, 0x00, 0x04, 0x00, 0x05,
|
||||
0x01, 0x00, 0x0a, 0x54, 0x65, 0x73, 0x74 };
|
||||
|
||||
int end [] = {
|
||||
0x01, 0x00, 0x10,
|
||||
0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e,
|
||||
0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
|
||||
0x00, 0x21, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04,
|
||||
0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00,
|
||||
0x00, 0x11, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x05, 0x2a, 0xb7, 0x00, 0x01, 0xb1, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
|
||||
// TestNNNNNN
|
||||
|
||||
String name = "Test" + Integer.toString(count++);
|
||||
|
||||
byte value[];
|
||||
try {
|
||||
value = name.substring(4).getBytes("UTF-8");
|
||||
} catch (java.io.UnsupportedEncodingException x) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
// construct class file
|
||||
|
||||
int len = begin.length + value.length + end.length;
|
||||
byte b[] = new byte[len];
|
||||
int pos=0;
|
||||
for (int i: begin) {
|
||||
b[pos++] = (byte) i;
|
||||
}
|
||||
for (byte v: value) {
|
||||
b[pos++] = v;
|
||||
}
|
||||
for (int e: end) {
|
||||
b[pos++] = (byte) e;
|
||||
}
|
||||
|
||||
return defineClass(name, b, 0, b.length);
|
||||
|
||||
}
|
||||
static int count = 100000;
|
||||
|
||||
}
|
||||
|
||||
public static void main(String s[]) {
|
||||
final MemoryMonitor demo = new MemoryMonitor();
|
||||
WindowListener l = new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {System.exit(0);}
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent e) { demo.surf.start(); }
|
||||
@Override
|
||||
public void windowIconified(WindowEvent e) { demo.surf.stop(); }
|
||||
};
|
||||
JFrame f = new JFrame("MemoryMonitor");
|
||||
f.addWindowListener(l);
|
||||
f.getContentPane().add("Center", demo);
|
||||
f.pack();
|
||||
f.setSize(new Dimension(400,500));
|
||||
f.setVisible(true);
|
||||
demo.surf.start();
|
||||
Thread thr = new Thread(new Memeater());
|
||||
thr.start();
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# - Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# - Neither the name of Oracle nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
MemoryMonitor demonstrates the use of the java.lang.management API
|
||||
in observing the memory usage of all memory pools consumed by
|
||||
the application.
|
||||
|
||||
This simple demo program queries the memory usage of each memory pool
|
||||
and plots the memory usage history graph.
|
||||
|
||||
To run the MemoryMonitor demo
|
||||
|
||||
java -jar <JDK_HOME>/demo/management/MemoryMonitor/MemoryMonitor.jar
|
||||
|
||||
These instructions assume that this installation's version of the java
|
||||
command is in your path. If it isn't, then you should either
|
||||
specify the complete path to the java command or update your
|
||||
PATH environment variable as described in the installation
|
||||
instructions for the Java(TM) SDK.
|
||||
|
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
import static java.lang.management.ManagementFactory.*;
|
||||
import java.lang.management.*;
|
||||
import javax.management.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Example of using the java.lang.management API to monitor
|
||||
* the memory usage and garbage collection statistics.
|
||||
*
|
||||
* @author Mandy Chung
|
||||
*/
|
||||
public class PrintGCStat {
|
||||
private RuntimeMXBean rmbean;
|
||||
private MemoryMXBean mmbean;
|
||||
private List<MemoryPoolMXBean> pools;
|
||||
private List<GarbageCollectorMXBean> gcmbeans;
|
||||
|
||||
/**
|
||||
* Constructs a PrintGCStat object to monitor a remote JVM.
|
||||
*/
|
||||
public PrintGCStat(MBeanServerConnection server) throws IOException {
|
||||
// Create the platform mxbean proxies
|
||||
this.rmbean = newPlatformMXBeanProxy(server,
|
||||
RUNTIME_MXBEAN_NAME,
|
||||
RuntimeMXBean.class);
|
||||
this.mmbean = newPlatformMXBeanProxy(server,
|
||||
MEMORY_MXBEAN_NAME,
|
||||
MemoryMXBean.class);
|
||||
ObjectName poolName = null;
|
||||
ObjectName gcName = null;
|
||||
try {
|
||||
poolName = new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE+",*");
|
||||
gcName = new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE+",*");
|
||||
} catch (MalformedObjectNameException e) {
|
||||
// should not reach here
|
||||
assert(false);
|
||||
}
|
||||
|
||||
Set<ObjectName> mbeans = server.queryNames(poolName, null);
|
||||
if (mbeans != null) {
|
||||
pools = new ArrayList<MemoryPoolMXBean>();
|
||||
for (ObjectName objName : mbeans) {
|
||||
MemoryPoolMXBean p =
|
||||
newPlatformMXBeanProxy(server,
|
||||
objName.getCanonicalName(),
|
||||
MemoryPoolMXBean.class);
|
||||
pools.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
mbeans = server.queryNames(gcName, null);
|
||||
if (mbeans != null) {
|
||||
gcmbeans = new ArrayList<GarbageCollectorMXBean>();
|
||||
for (ObjectName objName : mbeans) {
|
||||
GarbageCollectorMXBean gc =
|
||||
newPlatformMXBeanProxy(server,
|
||||
objName.getCanonicalName(),
|
||||
GarbageCollectorMXBean.class);
|
||||
gcmbeans.add(gc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a PrintGCStat object to monitor the local JVM.
|
||||
*/
|
||||
public PrintGCStat() {
|
||||
// Obtain the platform mxbean instances for the running JVM.
|
||||
this.rmbean = getRuntimeMXBean();
|
||||
this.mmbean = getMemoryMXBean();
|
||||
this.pools = getMemoryPoolMXBeans();
|
||||
this.gcmbeans = getGarbageCollectorMXBeans();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the verbose GC log to System.out to list the memory usage
|
||||
* of all memory pools as well as the GC statistics.
|
||||
*/
|
||||
public void printVerboseGc() {
|
||||
System.out.println("Uptime: " + formatMillis(rmbean.getUptime()));
|
||||
System.out.println("Heap usage: " + mmbean.getHeapMemoryUsage());
|
||||
System.out.println("Non-Heap memory usage: " + mmbean.getNonHeapMemoryUsage());
|
||||
for (GarbageCollectorMXBean gc : gcmbeans) {
|
||||
System.out.print(" [" + gc.getName() + ": ");
|
||||
System.out.print("Count=" + gc.getCollectionCount());
|
||||
System.out.print(" GCTime=" + formatMillis(gc.getCollectionTime()));
|
||||
System.out.print("]");
|
||||
}
|
||||
System.out.println();
|
||||
for (MemoryPoolMXBean p : pools) {
|
||||
System.out.print(" [" + p.getName() + ":");
|
||||
MemoryUsage u = p.getUsage();
|
||||
System.out.print(" Used=" + formatBytes(u.getUsed()));
|
||||
System.out.print(" Committed=" + formatBytes(u.getCommitted()));
|
||||
System.out.println("]");
|
||||
}
|
||||
}
|
||||
|
||||
private String formatMillis(long ms) {
|
||||
return String.format("%.4fsec", ms / (double) 1000);
|
||||
}
|
||||
private String formatBytes(long bytes) {
|
||||
long kb = bytes;
|
||||
if (bytes > 0) {
|
||||
kb = bytes / 1024;
|
||||
}
|
||||
return kb + "K";
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
VerboseGC demonstrates the use of the java.lang.management API to
|
||||
print the garbage collection statistics and memory usage remotely
|
||||
by connecting to a JMX agent with a JMX service URL:
|
||||
service:jmx:rmi:///jndi/rmi://<hostName>:<portNum>/jmxrmi
|
||||
where <hostName> is the hostname and <portNum> is the port number
|
||||
to which the JMX agent will be connected.
|
||||
|
||||
To run the VerboseGC demo
|
||||
|
||||
(1) Start the application with the JMX agent - here's an example of
|
||||
how the Java2D is started
|
||||
|
||||
java -Dcom.sun.management.jmxremote.port=1090
|
||||
-Dcom.sun.management.jmxremote.ssl=false
|
||||
-Dcom.sun.management.jmxremote.authenticate=false
|
||||
-jar <JDK_HOME>/demo/jfc/Java2D/Java2Demo.jar
|
||||
|
||||
This instruction uses the Sun's built-in support to enable a JMX agent.
|
||||
You can programmatically start a JMX agent with the RMI connector
|
||||
using javax.management.remote API. See the javadoc and examples for
|
||||
javax.management.remote API for details.
|
||||
|
||||
(2) Run VerboseGC
|
||||
|
||||
java -jar <JDK_HOME>/demo/management/VerboseGC/VerboseGC.jar localhost:1090
|
||||
|
||||
These instructions assume that this installation's version of the java
|
||||
command is in your path. If it isn't, then you should either
|
||||
specify the complete path to the java command or update your
|
||||
PATH environment variable as described in the installation
|
||||
instructions for the Java(TM) SDK.
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
import javax.management.*;
|
||||
import javax.management.remote.*;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
/**
|
||||
* This VerboseGC class demonstrates the capability to get
|
||||
* the garbage collection statistics and memory usage remotely.
|
||||
*/
|
||||
public class VerboseGC {
|
||||
private MBeanServerConnection server;
|
||||
private JMXConnector jmxc;
|
||||
public VerboseGC(String hostname, int port) {
|
||||
System.out.println("Connecting to " + hostname + ":" + port);
|
||||
|
||||
// Create an RMI connector client and connect it to
|
||||
// the RMI connector server
|
||||
String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
|
||||
connect(urlPath);
|
||||
}
|
||||
|
||||
public void dump(long interval, long samples) {
|
||||
try {
|
||||
PrintGCStat pstat = new PrintGCStat(server);
|
||||
for (int i = 0; i < samples; i++) {
|
||||
pstat.printVerboseGc();
|
||||
try {
|
||||
Thread.sleep(interval);
|
||||
} catch (InterruptedException e) {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("\nCommunication error: " + e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to a JMX agent of a given URL.
|
||||
*/
|
||||
private void connect(String urlPath) {
|
||||
try {
|
||||
JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
|
||||
this.jmxc = JMXConnectorFactory.connect(url);
|
||||
this.server = jmxc.getMBeanServerConnection();
|
||||
} catch (MalformedURLException e) {
|
||||
// should not reach here
|
||||
} catch (IOException e) {
|
||||
System.err.println("\nCommunication error: " + e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length < 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
String hostname = "";
|
||||
int port = -1;
|
||||
long interval = 5000; // default is 5 second interval
|
||||
long mins = 5;
|
||||
for (String arg: args) {
|
||||
if (arg.startsWith("-")) {
|
||||
if (arg.equals("-h") ||
|
||||
arg.equals("-help") ||
|
||||
arg.equals("-?")) {
|
||||
usage();
|
||||
} else if (arg.startsWith("-interval=")) {
|
||||
try {
|
||||
interval = Integer.parseInt(arg.substring(10)) * 1000;
|
||||
} catch (NumberFormatException ex) {
|
||||
usage();
|
||||
}
|
||||
} else if (arg.startsWith("-duration=")) {
|
||||
try {
|
||||
mins = Integer.parseInt(arg.substring(10));
|
||||
} catch (NumberFormatException ex) {
|
||||
usage();
|
||||
}
|
||||
} else {
|
||||
// Unknown switch
|
||||
System.err.println("Unrecognized option: " + arg);
|
||||
usage();
|
||||
}
|
||||
} else {
|
||||
String[] arg2 = arg.split(":");
|
||||
if (arg2.length != 2) {
|
||||
usage();
|
||||
}
|
||||
hostname = arg2[0];
|
||||
try {
|
||||
port = Integer.parseInt(arg2[1]);
|
||||
} catch (NumberFormatException x) {
|
||||
usage();
|
||||
}
|
||||
if (port < 0) {
|
||||
usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get full thread dump and perform deadlock detection
|
||||
VerboseGC vgc = new VerboseGC(hostname, port);
|
||||
long samples = (mins * 60 * 1000) / interval;
|
||||
vgc.dump(interval, samples);
|
||||
|
||||
}
|
||||
|
||||
private static void usage() {
|
||||
System.out.print("Usage: java VerboseGC <hostname>:<port> ");
|
||||
System.out.println(" [-interval=seconds] [-duration=minutes]");
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
<html>
|
||||
<head> <title>java.lang.management Demonstration Code</title> </head>
|
||||
|
||||
|
||||
<h1>java.lang.management Demonstration Code</h1>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<A HREF="FullThreadDump">FullThreadDump</A>
|
||||
<br>
|
||||
Shows how to get thread dumps and look for deadlocks.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="VerboseGC">VerboseGC</A>
|
||||
<br>
|
||||
Shows how you can find out about Garbage Collection in the VM.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="MemoryMonitor">MemoryMonitor</A>
|
||||
<br>
|
||||
Shows how you can find out the memory usage in the VM.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<A HREF="JTop">JTop</A>
|
||||
<br>
|
||||
Shows how you can find out the threads with top CPU usage.
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<h2>Comments and Feedback</h2>
|
||||
|
||||
<p>
|
||||
Comments regarding java.lang.management API or on any of these
|
||||
demonstrations should be sent through
|
||||
<A HREF="http://java.sun.com/mail">http://java.sun.com/mail/</A>
|
||||
|
||||
|
||||
</html>
|
@ -1,64 +0,0 @@
|
||||
What is this demo about?
|
||||
|
||||
This is "script shell" plugin for jconsole - the monitoring and management
|
||||
client tool shipped with JRE. This plugin adds "Script Shell" tab to jconsole.
|
||||
This serves as a demo for jconsole plugin API (com.sun.tools.jconsole) as well
|
||||
as a demo for scripting API (javax.script) for the Java platform.
|
||||
|
||||
Script console is an interactive read-eval-print interface that can be used
|
||||
used to execute advanced monitoring and management queries. By default,
|
||||
JavaScript is used as the scripting language. The scripting language can be
|
||||
changed using the system property com.sun.demo.jconsole.console.language. To
|
||||
use other scripting languages, you need to specify the corresponding engine
|
||||
jar file in pluginpath along with this plugin's jar file.
|
||||
|
||||
The following 3 global variables are exposed to the script engine:
|
||||
|
||||
window javax.swing.JPanel
|
||||
engine javax.script.ScriptEngine
|
||||
plugin com.sun.tools.jconsole.JConsolePlugin
|
||||
|
||||
If you use JavaScript, there are many useful global functions defined in
|
||||
./src/resources/jconsole.js. This is built into the script plugin jar file.
|
||||
In addition, you can add other global functions and global variables by
|
||||
defining those in ~/jconsole.js (or jconsole.<ext> where <ext> is the file
|
||||
extension for your scripting language of choice under your home directory).
|
||||
|
||||
How do I compile script console plugin?
|
||||
|
||||
You can use the Java based build tool "ant" (http://ant.apache.org) to build
|
||||
this plugin. To build using ant, please use the following command in the
|
||||
current directory:
|
||||
|
||||
ant
|
||||
|
||||
How do I use script console plugin?
|
||||
|
||||
To start jconsole with this plugin, please use the following command
|
||||
|
||||
jconsole -pluginpath jconsole-plugin.jar
|
||||
|
||||
How do I load my own script files in script console?
|
||||
|
||||
If you use JavaScript (the default), then there is a global function called
|
||||
"load" to load any script file from your file system. In script console
|
||||
prompt, enter the following:
|
||||
|
||||
load(<script-file-path>);
|
||||
|
||||
where <script-file-path> is the path of your script file to load. If you don't
|
||||
specify the file path, then the load function shows file dialog box to choose
|
||||
the script file to load.
|
||||
|
||||
How do I get help on script global functions?
|
||||
|
||||
If you use JavaScript (the default), then there is a global function called
|
||||
"help" that prints one-line help messages on global functions. In script
|
||||
console prompt, enter the following:
|
||||
|
||||
help();
|
||||
|
||||
Where are the sample JavaScript files?
|
||||
|
||||
./src/scripts directory contains JavaScript files that can be loaded into
|
||||
script console.
|
@ -1,86 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Oracle nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
This is ant (http://ant.apache.org) build script to build the jconsole
|
||||
script console plugin.
|
||||
-->
|
||||
|
||||
<project name="JConsole Script Shell Plugin" default="all" basedir=".">
|
||||
|
||||
<!-- property definitions -->
|
||||
<property name="app.name" value="jconsole-plugin"/>
|
||||
<property name="src.dir" value="src"/>
|
||||
<property name="jconsole.jar.dir" value="${java.home}/../lib"/>
|
||||
<property name="build.dir" value="."/>
|
||||
<property name="dist.jar" value="${build.dir}/${app.name}.jar"/>
|
||||
<property name="classes.dir" value="${build.dir}/classes"/>
|
||||
<property name="resources.dir" value="${classes.dir}/resources"/>
|
||||
|
||||
|
||||
<!-- make directories required -->
|
||||
<target name="prepare">
|
||||
<mkdir dir="${classes.dir}"/>
|
||||
</target>
|
||||
|
||||
<target name="clean">
|
||||
<delete file="${dist.jar}"/>
|
||||
<delete dir="${classes.dir}"/>
|
||||
</target>
|
||||
|
||||
<!-- we need jconsole.jar in CLASSPATH to build -->
|
||||
<path id="javac.classpath">
|
||||
<pathelement path="${jconsole.jar.dir}/jconsole.jar" />
|
||||
</path>
|
||||
|
||||
<target name="compile" depends="prepare" description="compiles the sources">
|
||||
<javac srcdir="${src.dir}"
|
||||
destdir="${classes.dir}"
|
||||
debug="on" deprecation="on">
|
||||
<classpath refid="javac.classpath" />
|
||||
</javac>
|
||||
<copy todir="${classes.dir}/META-INF/services">
|
||||
<fileset dir="${src.dir}/META-INF/services"/>
|
||||
</copy>
|
||||
<copy todir="${resources.dir}">
|
||||
<fileset dir="${src.dir}/resources"/>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="all" depends="compile" description="buile deployment bundle">
|
||||
<jar jarfile="${dist.jar}"
|
||||
basedir="${classes.dir}"/>
|
||||
</target>
|
||||
|
||||
</project>
|
@ -1 +0,0 @@
|
||||
com.sun.demo.scripting.jconsole.ScriptJConsolePlugin
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.sun.demo.scripting.jconsole;
|
||||
|
||||
import javax.swing.text.*;
|
||||
|
||||
/** This class implements a special type of document in which edits
|
||||
* can only be performed at the end, from "mark" to the end of the
|
||||
* document. This is used in ScriptShellPanel class as document for editor.
|
||||
*/
|
||||
public class EditableAtEndDocument extends PlainDocument {
|
||||
|
||||
private static final long serialVersionUID = 5358116444851502167L;
|
||||
private int mark;
|
||||
|
||||
@Override
|
||||
public void insertString(int offset, String text, AttributeSet a)
|
||||
throws BadLocationException {
|
||||
int len = getLength();
|
||||
super.insertString(len, text, a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(int offs, int len) throws BadLocationException {
|
||||
int start = offs;
|
||||
int end = offs + len;
|
||||
|
||||
int markStart = mark;
|
||||
int markEnd = getLength();
|
||||
|
||||
if ((end < markStart) || (start > markEnd)) {
|
||||
// no overlap
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine interval intersection
|
||||
int cutStart = Math.max(start, markStart);
|
||||
int cutEnd = Math.min(end, markEnd);
|
||||
super.remove(cutStart, cutEnd - cutStart);
|
||||
}
|
||||
|
||||
public void setMark() {
|
||||
mark = getLength();
|
||||
}
|
||||
|
||||
public String getMarkedText() throws BadLocationException {
|
||||
return getText(mark, getLength() - mark);
|
||||
}
|
||||
|
||||
/** Used to reset the contents of this document */
|
||||
public void clear() {
|
||||
try {
|
||||
super.remove(0, getLength());
|
||||
setMark();
|
||||
} catch (BadLocationException e) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.sun.demo.scripting.jconsole;
|
||||
|
||||
import com.sun.tools.jconsole.*;
|
||||
import java.io.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import javax.script.*;
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This is script console plugin. This class uses javax.script API to create
|
||||
* interactive read-eval-print script shell within the jconsole GUI.
|
||||
*/
|
||||
public class ScriptJConsolePlugin extends JConsolePlugin
|
||||
implements ScriptShellPanel.CommandProcessor {
|
||||
// Panel for our tab
|
||||
private volatile ScriptShellPanel window;
|
||||
// Tabs that we add to jconsole GUI
|
||||
private Map<String, JPanel> tabs;
|
||||
|
||||
// Script engine that evaluates scripts
|
||||
private volatile ScriptEngine engine;
|
||||
|
||||
// script engine initialization occurs in background.
|
||||
// This latch is used to coorrdinate engine init and eval.
|
||||
private CountDownLatch engineReady = new CountDownLatch(1);
|
||||
|
||||
// File extension used for scripts of chosen language.
|
||||
// For eg. ".js" for JavaScript, ".bsh" for BeanShell.
|
||||
private String extension;
|
||||
|
||||
// Prompt to print in the read-eval-print loop. This is
|
||||
// derived from the script file extension.
|
||||
private volatile String prompt;
|
||||
|
||||
/**
|
||||
* Constructor to create this plugin
|
||||
*/
|
||||
public ScriptJConsolePlugin() {
|
||||
}
|
||||
|
||||
@Override public Map<String, JPanel> getTabs() {
|
||||
// create ScriptEngine
|
||||
createScriptEngine();
|
||||
|
||||
// create panel for tab
|
||||
window = new ScriptShellPanel(this);
|
||||
|
||||
// add tab to tabs map
|
||||
tabs = new HashMap<String, JPanel>();
|
||||
tabs.put("Script Shell", window);
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// initialize the script engine
|
||||
initScriptEngine();
|
||||
engineReady.countDown();
|
||||
}
|
||||
}).start();
|
||||
return tabs;
|
||||
}
|
||||
|
||||
@Override public SwingWorker<?,?> newSwingWorker() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void dispose() {
|
||||
window.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String executeCommand(String cmd) {
|
||||
String res;
|
||||
try {
|
||||
engineReady.await();
|
||||
Object tmp = engine.eval(cmd);
|
||||
res = (tmp == null)? null : tmp.toString();
|
||||
} catch (InterruptedException ie) {
|
||||
res = ie.getMessage();
|
||||
} catch (ScriptException se) {
|
||||
res = se.getMessage();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//-- Internals only below this point
|
||||
private void createScriptEngine() {
|
||||
ScriptEngineManager manager = new ScriptEngineManager();
|
||||
String language = getScriptLanguage();
|
||||
engine = manager.getEngineByName(language);
|
||||
if (engine == null) {
|
||||
throw new RuntimeException("cannot load " + language + " engine");
|
||||
}
|
||||
extension = engine.getFactory().getExtensions().get(0);
|
||||
prompt = extension + ">";
|
||||
engine.setBindings(createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
}
|
||||
|
||||
// Name of the System property used to select scripting language
|
||||
private static final String LANGUAGE_KEY = "com.sun.demo.jconsole.console.language";
|
||||
|
||||
private String getScriptLanguage() {
|
||||
// check whether explicit System property is set
|
||||
String lang = System.getProperty(LANGUAGE_KEY);
|
||||
if (lang == null) {
|
||||
// default is JavaScript
|
||||
lang = "JavaScript";
|
||||
}
|
||||
return lang;
|
||||
}
|
||||
|
||||
// create Bindings that is backed by a synchronized HashMap
|
||||
private Bindings createBindings() {
|
||||
Map<String, Object> map =
|
||||
Collections.synchronizedMap(new HashMap<String, Object>());
|
||||
return new SimpleBindings(map);
|
||||
}
|
||||
|
||||
// create and initialize script engine
|
||||
private void initScriptEngine() {
|
||||
// set pre-defined global variables
|
||||
setGlobals();
|
||||
// load pre-defined initialization file
|
||||
loadInitFile();
|
||||
// load current user's initialization file
|
||||
loadUserInitFile();
|
||||
}
|
||||
|
||||
// set pre-defined global variables for script
|
||||
private void setGlobals() {
|
||||
engine.put("engine", engine);
|
||||
engine.put("window", window);
|
||||
engine.put("plugin", this);
|
||||
}
|
||||
|
||||
// load initial script file (jconsole.<extension>)
|
||||
private void loadInitFile() {
|
||||
String oldFilename = (String) engine.get(ScriptEngine.FILENAME);
|
||||
engine.put(ScriptEngine.FILENAME, "<built-in jconsole." + extension + ">");
|
||||
try {
|
||||
Class<? extends ScriptJConsolePlugin> myClass = this.getClass();
|
||||
InputStream stream = myClass.getResourceAsStream("/resources/jconsole." +
|
||||
extension);
|
||||
if (stream != null) {
|
||||
engine.eval(new InputStreamReader(new BufferedInputStream(stream)));
|
||||
}
|
||||
} catch (Exception exp) {
|
||||
exp.printStackTrace();
|
||||
// FIXME: What else I can do here??
|
||||
} finally {
|
||||
engine.put(ScriptEngine.FILENAME, oldFilename);
|
||||
}
|
||||
}
|
||||
|
||||
// load user's initial script file (~/jconsole.<extension>)
|
||||
private void loadUserInitFile() {
|
||||
String oldFilename = (String) engine.get(ScriptEngine.FILENAME);
|
||||
String home = System.getProperty("user.home");
|
||||
if (home == null) {
|
||||
// no user.home?? should not happen??
|
||||
return;
|
||||
}
|
||||
String fileName = home + File.separator + "jconsole." + extension;
|
||||
if (! (new File(fileName).exists())) {
|
||||
// user does not have ~/jconsole.<extension>
|
||||
return;
|
||||
}
|
||||
engine.put(ScriptEngine.FILENAME, fileName);
|
||||
try {
|
||||
engine.eval(new FileReader(fileName));
|
||||
} catch (Exception exp) {
|
||||
exp.printStackTrace();
|
||||
// FIXME: What else I can do here??
|
||||
} finally {
|
||||
engine.put(ScriptEngine.FILENAME, oldFilename);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,263 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.sun.demo.scripting.jconsole;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.text.*;
|
||||
|
||||
|
||||
/**
|
||||
* A JPanel subclass containing a scrollable text area displaying the
|
||||
* jconsole's script console.
|
||||
*/
|
||||
|
||||
public class ScriptShellPanel extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = 4116273141148726319L;
|
||||
|
||||
// interface to evaluate script command and script prompt
|
||||
interface CommandProcessor {
|
||||
// execute given String as script and return the result
|
||||
public String executeCommand(String cmd);
|
||||
// get prompt used for interactive read-eval-loop
|
||||
public String getPrompt();
|
||||
}
|
||||
|
||||
// my script command processor
|
||||
private CommandProcessor commandProcessor;
|
||||
// editor component for command editing
|
||||
private JTextComponent editor;
|
||||
|
||||
private final ExecutorService commandExecutor =
|
||||
Executors.newSingleThreadExecutor();
|
||||
|
||||
// document management
|
||||
private boolean updating;
|
||||
|
||||
public ScriptShellPanel(CommandProcessor cmdProc) {
|
||||
setLayout(new BorderLayout());
|
||||
this.commandProcessor = cmdProc;
|
||||
this.editor = new JTextArea();
|
||||
editor.setDocument(new EditableAtEndDocument());
|
||||
JScrollPane scroller = new JScrollPane();
|
||||
scroller.getViewport().add(editor);
|
||||
add(scroller, BorderLayout.CENTER);
|
||||
|
||||
editor.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
if (updating) return;
|
||||
beginUpdate();
|
||||
editor.setCaretPosition(editor.getDocument().getLength());
|
||||
if (insertContains(e, '\n')) {
|
||||
String cmd = getMarkedText();
|
||||
// Handle multi-line input
|
||||
if ((cmd.length() == 0) ||
|
||||
(cmd.charAt(cmd.length() - 1) != '\\')) {
|
||||
// Trim "\\n" combinations
|
||||
final String cmd1 = trimContinuations(cmd);
|
||||
commandExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final String result = executeCommand(cmd1);
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (result != null) {
|
||||
print(result + "\n");
|
||||
}
|
||||
printPrompt();
|
||||
setMark();
|
||||
endUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
endUpdate();
|
||||
}
|
||||
} else {
|
||||
endUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
}
|
||||
});
|
||||
|
||||
// This is a bit of a hack but is probably better than relying on
|
||||
// the JEditorPane to update the caret's position precisely the
|
||||
// size of the insertion
|
||||
editor.addCaretListener(new CaretListener() {
|
||||
@Override
|
||||
public void caretUpdate(CaretEvent e) {
|
||||
int len = editor.getDocument().getLength();
|
||||
if (e.getDot() > len) {
|
||||
editor.setCaretPosition(len);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Box hbox = Box.createHorizontalBox();
|
||||
hbox.add(Box.createGlue());
|
||||
JButton button = new JButton("Clear"); // FIXME: i18n?
|
||||
button.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
clear();
|
||||
}
|
||||
});
|
||||
hbox.add(button);
|
||||
hbox.add(Box.createGlue());
|
||||
add(hbox, BorderLayout.SOUTH);
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
commandExecutor.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFocus() {
|
||||
editor.requestFocus();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
clear(true);
|
||||
}
|
||||
|
||||
public void clear(boolean prompt) {
|
||||
EditableAtEndDocument d = (EditableAtEndDocument) editor.getDocument();
|
||||
d.clear();
|
||||
if (prompt) printPrompt();
|
||||
setMark();
|
||||
editor.requestFocus();
|
||||
}
|
||||
|
||||
public void setMark() {
|
||||
((EditableAtEndDocument) editor.getDocument()).setMark();
|
||||
}
|
||||
|
||||
public String getMarkedText() {
|
||||
try {
|
||||
String s = ((EditableAtEndDocument) editor.getDocument()).getMarkedText();
|
||||
int i = s.length();
|
||||
while ((i > 0) && (s.charAt(i - 1) == '\n')) {
|
||||
i--;
|
||||
}
|
||||
return s.substring(0, i);
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void print(String s) {
|
||||
Document d = editor.getDocument();
|
||||
try {
|
||||
d.insertString(d.getLength(), s, null);
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Internals only below this point
|
||||
//
|
||||
|
||||
private String executeCommand(String cmd) {
|
||||
return commandProcessor.executeCommand(cmd);
|
||||
}
|
||||
|
||||
private String getPrompt() {
|
||||
return commandProcessor.getPrompt();
|
||||
}
|
||||
|
||||
private void beginUpdate() {
|
||||
editor.setEditable(false);
|
||||
updating = true;
|
||||
}
|
||||
|
||||
private void endUpdate() {
|
||||
editor.setEditable(true);
|
||||
updating = false;
|
||||
}
|
||||
|
||||
private void printPrompt() {
|
||||
print(getPrompt());
|
||||
}
|
||||
|
||||
private boolean insertContains(DocumentEvent e, char c) {
|
||||
String s = null;
|
||||
try {
|
||||
s = editor.getText(e.getOffset(), e.getLength());
|
||||
for (int i = 0; i < e.getLength(); i++) {
|
||||
if (s.charAt(i) == c) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (BadLocationException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String trimContinuations(String text) {
|
||||
int i;
|
||||
while ((i = text.indexOf("\\\n")) >= 0) {
|
||||
text = text.substring(0, i) + text.substring(i+1, text.length());
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
@ -1,891 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* -Redistribution of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* -Redistribution in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of Oracle nor the names of contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* This software is provided "AS IS," without a warranty of any kind. ALL
|
||||
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
|
||||
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
|
||||
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
|
||||
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
|
||||
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
|
||||
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
|
||||
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
|
||||
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
|
||||
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
|
||||
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* You acknowledge that this software is not designed, licensed or intended
|
||||
* for use in the design, construction, operation or maintenance of any
|
||||
* nuclear facility.
|
||||
*/
|
||||
|
||||
// This function depends on the pre-defined variable
|
||||
// "plugin" of type com.sun.tools.jconsole.JConsolePlugin
|
||||
|
||||
function jcontext() {
|
||||
return plugin.getContext();
|
||||
}
|
||||
jcontext.docString = "returns JConsoleContext for the current jconsole plugin";
|
||||
|
||||
function mbeanConnection() {
|
||||
return jcontext().getMBeanServerConnection();
|
||||
}
|
||||
mbeanConnection.docString = "returns current MBeanServer connection";
|
||||
|
||||
// check if there is a build in sync function, define one if missing
|
||||
if (typeof sync === "undefined") {
|
||||
var sync = function(func, obj) {
|
||||
if (arguments.length < 1 || arguments.length > 2 ) {
|
||||
throw "sync(function [,object]) parameter count mismatch";
|
||||
}
|
||||
|
||||
var syncobj = (arguments.length == 2 ? obj : this);
|
||||
|
||||
if (!syncobj._syncLock) {
|
||||
syncobj._syncLock = new Lock();
|
||||
}
|
||||
|
||||
return function() {
|
||||
syncobj._syncLock.lock();
|
||||
try {
|
||||
func.apply(null, arguments);
|
||||
} finally {
|
||||
syncobj._syncLock.unlock();
|
||||
}
|
||||
};
|
||||
};
|
||||
sync.docString = "synchronize a function, optionally on an object";
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints one liner help message for each function exposed here
|
||||
* Note that this function depends on docString meta-data for
|
||||
* each function
|
||||
*/
|
||||
function help() {
|
||||
var i;
|
||||
for (i in this) {
|
||||
var func = this[i];
|
||||
if (typeof(func) == "function" &&
|
||||
("docString" in func)) {
|
||||
echo(i + " - " + func["docString"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
help.docString = "prints help message for global functions";
|
||||
|
||||
function connectionState() {
|
||||
return jcontext().connectionState;
|
||||
}
|
||||
connectionState.docString = "return connection state of the current jcontext";
|
||||
|
||||
/**
|
||||
* Returns a platform MXBean proxy for given MXBean name and interface class
|
||||
*/
|
||||
function newPlatformMXBeanProxy(name, intf) {
|
||||
var factory = java.lang.management.ManagementFactory;
|
||||
return factory.newPlatformMXBeanProxy(mbeanConnection(), name, intf);
|
||||
}
|
||||
newPlatformMXBeanProxy.docString = "returns a proxy for a platform MXBean";
|
||||
|
||||
/**
|
||||
* Wraps a string to ObjectName if needed.
|
||||
*/
|
||||
function objectName(objName) {
|
||||
var ObjectName = Packages.javax.management.ObjectName;
|
||||
if (objName instanceof ObjectName) {
|
||||
return objName;
|
||||
} else {
|
||||
return new ObjectName(objName);
|
||||
}
|
||||
}
|
||||
objectName.docString = "creates JMX ObjectName for a given String";
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new (M&M) Attribute object
|
||||
*
|
||||
* @param name name of the attribute
|
||||
* @param value value of the attribute
|
||||
*/
|
||||
function attribute(name, value) {
|
||||
var Attribute = Packages.javax.management.Attribute;
|
||||
return new Attribute(name, value);
|
||||
}
|
||||
attribute.docString = "returns a new JMX Attribute using name and value given";
|
||||
|
||||
/**
|
||||
* Returns MBeanInfo for given ObjectName. Strings are accepted.
|
||||
*/
|
||||
function mbeanInfo(objName) {
|
||||
objName = objectName(objName);
|
||||
return mbeanConnection().getMBeanInfo(objName);
|
||||
}
|
||||
mbeanInfo.docString = "returns MBeanInfo of a given ObjectName";
|
||||
|
||||
/**
|
||||
* Returns ObjectInstance for a given ObjectName.
|
||||
*/
|
||||
function objectInstance(objName) {
|
||||
objName = objectName(objName);
|
||||
return mbeanConnection().objectInstance(objectName);
|
||||
}
|
||||
objectInstance.docString = "returns ObjectInstance for a given ObjectName";
|
||||
|
||||
/**
|
||||
* Queries with given ObjectName and QueryExp.
|
||||
* QueryExp may be null.
|
||||
*
|
||||
* @return set of ObjectNames.
|
||||
*/
|
||||
function queryNames(objName, query) {
|
||||
objName = objectName(objName);
|
||||
if (query == undefined) query = null;
|
||||
return mbeanConnection().queryNames(objName, query);
|
||||
}
|
||||
queryNames.docString = "returns QueryNames using given ObjectName and optional query";
|
||||
|
||||
|
||||
/**
|
||||
* Queries with given ObjectName and QueryExp.
|
||||
* QueryExp may be null.
|
||||
*
|
||||
* @return set of ObjectInstances.
|
||||
*/
|
||||
function queryMBeans(objName, query) {
|
||||
objName = objectName(objName);
|
||||
if (query == undefined) query = null;
|
||||
return mbeanConnection().queryMBeans(objName, query);
|
||||
}
|
||||
queryMBeans.docString = "return MBeans using given ObjectName and optional query";
|
||||
|
||||
// wraps a script array as java.lang.Object[]
|
||||
function objectArray(array) {
|
||||
return Java.to(array, "java.lang.Object[]");
|
||||
}
|
||||
|
||||
// wraps a script (string) array as java.lang.String[]
|
||||
function stringArray(array) {
|
||||
return Java.to(array, "java.lang.String[]");
|
||||
}
|
||||
|
||||
// script array to Java List
|
||||
function toAttrList(array) {
|
||||
var AttributeList = Packages.javax.management.AttributeList;
|
||||
if (array instanceof AttributeList) {
|
||||
return array;
|
||||
}
|
||||
var list = new AttributeList(array.length);
|
||||
for (var index = 0; index < array.length; index++) {
|
||||
list.add(array[index]);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// Java Collection (Iterable) to script array
|
||||
function toArray(collection) {
|
||||
if (collection instanceof Array) {
|
||||
return collection;
|
||||
}
|
||||
var itr = collection.iterator();
|
||||
var array = new Array();
|
||||
while (itr.hasNext()) {
|
||||
array[array.length] = itr.next();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
// gets MBean attributes
|
||||
function getMBeanAttributes(objName, attributeNames) {
|
||||
objName = objectName(objName);
|
||||
return mbeanConnection().getAttributes(objName,stringArray(attributeNames));
|
||||
}
|
||||
getMBeanAttributes.docString = "returns specified Attributes of given ObjectName";
|
||||
|
||||
// gets MBean attribute
|
||||
function getMBeanAttribute(objName, attrName) {
|
||||
objName = objectName(objName);
|
||||
return mbeanConnection().getAttribute(objName, attrName);
|
||||
}
|
||||
getMBeanAttribute.docString = "returns a single Attribute of given ObjectName";
|
||||
|
||||
|
||||
// sets MBean attributes
|
||||
function setMBeanAttributes(objName, attrList) {
|
||||
objName = objectName(objName);
|
||||
attrList = toAttrList(attrList);
|
||||
return mbeanConnection().setAttributes(objName, attrList);
|
||||
}
|
||||
setMBeanAttributes.docString = "sets specified Attributes of given ObjectName";
|
||||
|
||||
// sets MBean attribute
|
||||
function setMBeanAttribute(objName, attrName, attrValue) {
|
||||
var Attribute = Packages.javax.management.Attribute;
|
||||
objName = objectName(objName);
|
||||
mbeanConnection().setAttribute(objName, new Attribute(attrName, attrValue));
|
||||
}
|
||||
setMBeanAttribute.docString = "sets a single Attribute of given ObjectName";
|
||||
|
||||
|
||||
// invokes an operation on given MBean
|
||||
function invokeMBean(objName, operation, params, signature) {
|
||||
objName = objectName(objName);
|
||||
params = objectArray(params);
|
||||
signature = stringArray(signature);
|
||||
return mbeanConnection().invoke(objName, operation, params, signature);
|
||||
}
|
||||
invokeMBean.docString = "invokes MBean operation on given ObjectName";
|
||||
|
||||
/**
|
||||
* Wraps a MBean specified by ObjectName as a convenient
|
||||
* script object -- so that setting/getting MBean attributes
|
||||
* and invoking MBean method can be done with natural syntax.
|
||||
*
|
||||
* @param objName ObjectName of the MBean
|
||||
* @param async asynchornous mode [optional, default is false]
|
||||
* @return script wrapper for MBean
|
||||
*
|
||||
* With async mode, all field, operation access is async. Results
|
||||
* will be of type FutureTask. When you need value, call 'get' on it.
|
||||
*/
|
||||
function mbean(objName, async) {
|
||||
var index;
|
||||
|
||||
objName = objectName(objName);
|
||||
var info = mbeanInfo(objName);
|
||||
var attrs = info.attributes;
|
||||
var attrMap = new Object;
|
||||
for (index in attrs) {
|
||||
attrMap[attrs[index].name] = attrs[index];
|
||||
}
|
||||
var opers = info.operations;
|
||||
var operMap = new Object;
|
||||
for (index in opers) {
|
||||
operMap[opers[index].name] = opers[index];
|
||||
}
|
||||
|
||||
function isAttribute(name) {
|
||||
return name in attrMap;
|
||||
}
|
||||
|
||||
function isOperation(name) {
|
||||
return name in operMap;
|
||||
}
|
||||
|
||||
return new JSAdapter() {
|
||||
__has__: function (name) {
|
||||
return isAttribute(name) || isOperation(name);
|
||||
},
|
||||
__get__: function (name) {
|
||||
if (isAttribute(name)) {
|
||||
if (async) {
|
||||
return getMBeanAttribute.future(objName, name);
|
||||
} else {
|
||||
return getMBeanAttribute(objName, name);
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
__call__: function(name) {
|
||||
if (isOperation(name)) {
|
||||
var oper = operMap[name];
|
||||
|
||||
var params = [];
|
||||
for (var j = 1; j < arguments.length; j++) {
|
||||
params[j-1]= arguments[j];
|
||||
}
|
||||
|
||||
var sigs = oper.signature;
|
||||
|
||||
var sigNames = new Array(sigs.length);
|
||||
for (var index in sigs) {
|
||||
sigNames[index] = sigs[index].getType();
|
||||
}
|
||||
|
||||
if (async) {
|
||||
return invokeMBean.future(objName, name, params, sigNames);
|
||||
} else {
|
||||
return invokeMBean(objName, name, params, sigNames);
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
__put__: function (name, value) {
|
||||
if (isAttribute(name)) {
|
||||
if (async) {
|
||||
setMBeanAttribute.future(objName, name, value);
|
||||
} else {
|
||||
setMBeanAttribute(objName, name, value);
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
mbean.docString = "returns a conveninent script wrapper for a MBean of given ObjectName";
|
||||
|
||||
/**
|
||||
* load and evaluate script file. If no script file is
|
||||
* specified, file dialog is shown to choose the script.
|
||||
*
|
||||
* @param file script file name [optional]
|
||||
* @return value returned from evaluating script
|
||||
*/
|
||||
function load(file) {
|
||||
if (file == undefined || file == null) {
|
||||
// file not specified, show file dialog to choose
|
||||
file = fileDialog();
|
||||
}
|
||||
if (file == null) return;
|
||||
|
||||
var reader = new java.io.FileReader(file);
|
||||
var oldFilename = engine.get(engine.FILENAME);
|
||||
engine.put(engine.FILENAME, file);
|
||||
try {
|
||||
engine.eval(reader);
|
||||
} finally {
|
||||
engine.put(engine.FILENAME, oldFilename);
|
||||
}
|
||||
reader.close();
|
||||
}
|
||||
load.docString = "loads a script file and evaluates it";
|
||||
|
||||
/**
|
||||
* Concurrency utilities for JavaScript. These are based on
|
||||
* java.lang and java.util.concurrent API. The following functions
|
||||
* provide a simpler API for scripts. Instead of directly using java.lang
|
||||
* and java.util.concurrent classes, scripts can use functions and
|
||||
* objects exported from here.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Wrapper for java.lang.Object.wait
|
||||
*
|
||||
* can be called only within a sync method
|
||||
*/
|
||||
function wait(object) {
|
||||
var objClazz = java.lang.Class.forName('java.lang.Object');
|
||||
var waitMethod = objClazz.getMethod('wait', null);
|
||||
waitMethod.invoke(object, null);
|
||||
}
|
||||
wait.docString = "convenient wrapper for java.lang.Object.wait method";
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for java.lang.Object.notify
|
||||
*
|
||||
* can be called only within a sync method
|
||||
*/
|
||||
function notify(object) {
|
||||
var objClazz = java.lang.Class.forName('java.lang.Object');
|
||||
var notifyMethod = objClazz.getMethod('notify', null);
|
||||
notifyMethod.invoke(object, null);
|
||||
}
|
||||
notify.docString = "convenient wrapper for java.lang.Object.notify method";
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for java.lang.Object.notifyAll
|
||||
*
|
||||
* can be called only within a sync method
|
||||
*/
|
||||
function notifyAll(object) {
|
||||
var objClazz = java.lang.Class.forName('java.lang.Object');
|
||||
var notifyAllMethod = objClazz.getMethod('notifyAll', null);
|
||||
notifyAllMethod.invoke(object, null);
|
||||
}
|
||||
notifyAll.docString = "convenient wrapper for java.lang.Object.notifyAll method";
|
||||
|
||||
|
||||
/**
|
||||
* Creates a java.lang.Runnable from a given script
|
||||
* function.
|
||||
*/
|
||||
Function.prototype.runnable = function() {
|
||||
var args = arguments;
|
||||
var func = this;
|
||||
return new java.lang.Runnable() {
|
||||
run: function() {
|
||||
func.apply(null, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the function on a new Java Thread.
|
||||
*/
|
||||
Function.prototype.thread = function() {
|
||||
var t = new java.lang.Thread(this.runnable.apply(this, arguments));
|
||||
t.start();
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the function on a new Java daemon Thread.
|
||||
*/
|
||||
Function.prototype.daemon = function() {
|
||||
var t = new java.lang.Thread(this.runnable.apply(this, arguments));
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a java.util.concurrent.Callable from a given script
|
||||
* function.
|
||||
*/
|
||||
Function.prototype.callable = function() {
|
||||
var args = arguments;
|
||||
var func = this;
|
||||
return new java.util.concurrent.Callable() {
|
||||
call: function() { return func.apply(null, args); }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the script function so that it will be called exit.
|
||||
*/
|
||||
Function.prototype.atexit = function () {
|
||||
var args = arguments;
|
||||
java.lang.Runtime.getRuntime().addShutdownHook(
|
||||
new java.lang.Thread(this.runnable.apply(this, args)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the function asynchronously.
|
||||
*
|
||||
* @return a java.util.concurrent.FutureTask
|
||||
*/
|
||||
Function.prototype.future = (function() {
|
||||
// default executor for future
|
||||
var juc = java.util.concurrent;
|
||||
var theExecutor = juc.Executors.newSingleThreadExecutor();
|
||||
// clean-up the default executor at exit
|
||||
(function() { theExecutor.shutdown(); }).atexit();
|
||||
return function() {
|
||||
return theExecutor.submit(this.callable.apply(this, arguments));
|
||||
}
|
||||
})();
|
||||
|
||||
// shortcut for j.u.c lock classes
|
||||
var Lock = java.util.concurrent.locks.ReentrantLock;
|
||||
var RWLock = java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* Executes a function after acquiring given lock. On return,
|
||||
* (normal or exceptional), lock is released.
|
||||
*
|
||||
* @param lock lock that is locked and unlocked
|
||||
*/
|
||||
Function.prototype.sync = function (lock) {
|
||||
if (arguments.length == 0) {
|
||||
throw "lock is missing";
|
||||
}
|
||||
var res = new Array(arguments.length - 1);
|
||||
for (var i = 0; i < res.length; i++) {
|
||||
res[i] = arguments[i + 1];
|
||||
}
|
||||
lock.lock();
|
||||
try {
|
||||
this.apply(null, res);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Causes current thread to sleep for specified
|
||||
* number of milliseconds
|
||||
*
|
||||
* @param interval in milliseconds
|
||||
*/
|
||||
function sleep(interval) {
|
||||
java.lang.Thread.sleep(interval);
|
||||
}
|
||||
sleep.docString = "wrapper for java.lang.Thread.sleep method";
|
||||
|
||||
/**
|
||||
* Schedules a task to be executed once in N milliseconds specified.
|
||||
*
|
||||
* @param callback function or expression to evaluate
|
||||
* @param interval in milliseconds to sleep
|
||||
* @return timeout ID (which is nothing but Thread instance)
|
||||
*/
|
||||
function setTimeout(callback, interval) {
|
||||
if (! (callback instanceof Function)) {
|
||||
callback = new Function(callback);
|
||||
}
|
||||
|
||||
// start a new thread that sleeps given time
|
||||
// and calls callback in an infinite loop
|
||||
return (function() {
|
||||
try {
|
||||
sleep(interval);
|
||||
} catch (x) { }
|
||||
callback();
|
||||
}).daemon();
|
||||
}
|
||||
setTimeout.docString = "calls given callback once after specified interval";
|
||||
|
||||
/**
|
||||
* Cancels a timeout set earlier.
|
||||
* @param tid timeout ID returned from setTimeout
|
||||
*/
|
||||
function clearTimeout(tid) {
|
||||
// we just interrupt the timer thread
|
||||
tid.interrupt();
|
||||
}
|
||||
clearTimeout.docString = "interrupt a setTimeout timer";
|
||||
|
||||
/**
|
||||
* Schedules a task to be executed once in
|
||||
* every N milliseconds specified.
|
||||
*
|
||||
* @param callback function or expression to evaluate
|
||||
* @param interval in milliseconds to sleep
|
||||
* @return timeout ID (which is nothing but Thread instance)
|
||||
*/
|
||||
function setInterval(callback, interval) {
|
||||
if (! (callback instanceof Function)) {
|
||||
callback = new Function(callback);
|
||||
}
|
||||
|
||||
// start a new thread that sleeps given time
|
||||
// and calls callback in an infinite loop
|
||||
return (function() {
|
||||
while (true) {
|
||||
try {
|
||||
sleep(interval);
|
||||
} catch (x) {
|
||||
break;
|
||||
}
|
||||
callback();
|
||||
}
|
||||
}).daemon();
|
||||
}
|
||||
setInterval.docString = "calls given callback every specified interval";
|
||||
|
||||
/**
|
||||
* Cancels a timeout set earlier.
|
||||
* @param tid timeout ID returned from setTimeout
|
||||
*/
|
||||
function clearInterval(tid) {
|
||||
// we just interrupt the timer thread
|
||||
tid.interrupt();
|
||||
}
|
||||
clearInterval.docString = "interrupt a setInterval timer";
|
||||
|
||||
/**
|
||||
* Simple access to thread local storage.
|
||||
*
|
||||
* Script sample:
|
||||
*
|
||||
* __thread.x = 44;
|
||||
* function f() {
|
||||
* __thread.x = 'hello';
|
||||
* print(__thread.x);
|
||||
* }
|
||||
* f.thread(); // prints 'hello'
|
||||
* print(__thread.x); // prints 44 in main thread
|
||||
*/
|
||||
var __thread = (function () {
|
||||
var map = new Object();
|
||||
return new JSAdapter() {
|
||||
__has__: function(name) {
|
||||
return map[name] != undefined;
|
||||
},
|
||||
__get__: function(name) {
|
||||
if (map[name] != undefined) {
|
||||
return map[name].get();
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
__put__: sync(function(name, value) {
|
||||
if (map[name] == undefined) {
|
||||
var tmp = new java.lang.ThreadLocal();
|
||||
tmp.set(value);
|
||||
map[name] = tmp;
|
||||
} else {
|
||||
map[name].set(value);
|
||||
}
|
||||
}),
|
||||
__delete__: function(name) {
|
||||
if (map[name] != undefined) {
|
||||
map[name].set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// user interface utilities
|
||||
|
||||
/**
|
||||
* Swing invokeLater - invokes given function in AWT event thread
|
||||
*/
|
||||
Function.prototype.invokeLater = function() {
|
||||
var SwingUtilities = Packages.javax.swing.SwingUtilities;
|
||||
SwingUtilities.invokeLater(this.runnable.apply(this, arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Swing invokeAndWait - invokes given function in AWT event thread
|
||||
* and waits for it's completion
|
||||
*/
|
||||
Function.prototype.invokeAndWait = function() {
|
||||
var SwingUtilities = Packages.javax.swing.SwingUtilities;
|
||||
SwingUtilities.invokeAndWait(this.runnable.apply(this, arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Am I running in AWT event dispatcher thread?
|
||||
*/
|
||||
function isEventThread() {
|
||||
var SwingUtilities = Packages.javax.swing.SwingUtilities;
|
||||
return SwingUtilities.isEventDispatchThread();
|
||||
}
|
||||
isEventThread.docString = "returns whether the current thread is GUI thread";
|
||||
|
||||
/**
|
||||
* Opens a file dialog box
|
||||
*
|
||||
* @param curDir current directory [optional]
|
||||
* @return absolute path if file selected or else null
|
||||
*/
|
||||
function fileDialog(curDir) {
|
||||
var result;
|
||||
function _fileDialog() {
|
||||
if (curDir == undefined) curDir = undefined;
|
||||
var JFileChooser = Packages.javax.swing.JFileChooser;
|
||||
var dialog = new JFileChooser(curDir);
|
||||
var res = dialog.showOpenDialog(null);
|
||||
if (res == JFileChooser.APPROVE_OPTION) {
|
||||
result = dialog.getSelectedFile().getAbsolutePath();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (isEventThread()) {
|
||||
_fileDialog();
|
||||
} else {
|
||||
_fileDialog.invokeAndWait();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
fileDialog.docString = "show a FileOpen dialog box";
|
||||
|
||||
/**
|
||||
* Shows a message box
|
||||
*
|
||||
* @param msg message to be shown
|
||||
* @param title title of message box [optional]
|
||||
* @param msgType type of message box [constants in JOptionPane]
|
||||
*/
|
||||
function msgBox(msg, title, msgType) {
|
||||
|
||||
function _msgBox() {
|
||||
var JOptionPane = Packages.javax.swing.JOptionPane;
|
||||
if (msg === undefined) msg = "undefined";
|
||||
if (msg === null) msg = "null";
|
||||
if (title == undefined) title = msg;
|
||||
if (msgType == undefined) msgType = JOptionPane.INFORMATION_MESSAGE;
|
||||
JOptionPane.showMessageDialog(window, msg, title, msgType);
|
||||
}
|
||||
if (isEventThread()) {
|
||||
_msgBox();
|
||||
} else {
|
||||
_msgBox.invokeAndWait();
|
||||
}
|
||||
}
|
||||
msgBox.docString = "shows MessageBox to the user";
|
||||
|
||||
/**
|
||||
* Shows an information alert box
|
||||
*
|
||||
* @param msg message to be shown
|
||||
* @param title title of message box [optional]
|
||||
*/
|
||||
function alert(msg, title) {
|
||||
var JOptionPane = Packages.javax.swing.JOptionPane;
|
||||
msgBox(msg, title, JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
alert.docString = "shows an alert message box to the user";
|
||||
|
||||
/**
|
||||
* Shows an error alert box
|
||||
*
|
||||
* @param msg message to be shown
|
||||
* @param title title of message box [optional]
|
||||
*/
|
||||
function error(msg, title) {
|
||||
var JOptionPane = Packages.javax.swing.JOptionPane;
|
||||
msgBox(msg, title, JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
error.docString = "shows an error message box to the user";
|
||||
|
||||
|
||||
/**
|
||||
* Shows a warning alert box
|
||||
*
|
||||
* @param msg message to be shown
|
||||
* @param title title of message box [optional]
|
||||
*/
|
||||
function warn(msg, title) {
|
||||
var JOptionPane = Packages.javax.swing.JOptionPane;
|
||||
msgBox(msg, title, JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
warn.docString = "shows a warning message box to the user";
|
||||
|
||||
|
||||
/**
|
||||
* Shows a prompt dialog box
|
||||
*
|
||||
* @param question question to be asked
|
||||
* @param answer default answer suggested [optional]
|
||||
* @return answer given by user
|
||||
*/
|
||||
function prompt(question, answer) {
|
||||
var result;
|
||||
function _prompt() {
|
||||
var JOptionPane = Packages.javax.swing.JOptionPane;
|
||||
if (answer == undefined) answer = "";
|
||||
result = JOptionPane.showInputDialog(window, question, answer);
|
||||
}
|
||||
if (isEventThread()) {
|
||||
_prompt();
|
||||
} else {
|
||||
_prompt.invokeAndWait();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
prompt.docString = "shows a prompt box to the user and returns the answer";
|
||||
|
||||
/**
|
||||
* Shows a confirmation dialog box
|
||||
*
|
||||
* @param msg message to be shown
|
||||
* @param title title of message box [optional]
|
||||
* @return boolean (yes->true, no->false)
|
||||
*/
|
||||
function confirm(msg, title) {
|
||||
var result;
|
||||
var JOptionPane = Packages.javax.swing.JOptionPane;
|
||||
function _confirm() {
|
||||
if (title == undefined) title = msg;
|
||||
var optionType = JOptionPane.YES_NO_OPTION;
|
||||
result = JOptionPane.showConfirmDialog(null, msg, title, optionType);
|
||||
}
|
||||
if (isEventThread()) {
|
||||
_confirm();
|
||||
} else {
|
||||
_confirm.invokeAndWait();
|
||||
}
|
||||
return result == JOptionPane.YES_OPTION;
|
||||
}
|
||||
confirm.docString = "shows a confirmation message box to the user";
|
||||
|
||||
/**
|
||||
* Echoes zero or more arguments supplied to screen.
|
||||
* This is print equivalent for GUI.
|
||||
*
|
||||
* @param zero or more items to echo.
|
||||
*/
|
||||
function echo() {
|
||||
var args = arguments;
|
||||
(function() {
|
||||
var len = args.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
window.print(args[i]);
|
||||
window.print(" ");
|
||||
}
|
||||
window.print("\n");
|
||||
}).invokeLater();
|
||||
}
|
||||
echo.docString = "echoes arguments to interactive console screen";
|
||||
|
||||
|
||||
/**
|
||||
* Clear the screen
|
||||
*/
|
||||
function clear() {
|
||||
(function() { window.clear(false); }).invokeLater();
|
||||
}
|
||||
clear.docString = "clears interactive console screen";
|
||||
|
||||
|
||||
// synonym for clear
|
||||
var cls = clear;
|
||||
|
||||
|
||||
/**
|
||||
* Exit the process after confirmation from user
|
||||
*
|
||||
* @param exitCode return code to OS [optional]
|
||||
*/
|
||||
function exit(exitCode) {
|
||||
if (exitCode == undefined) exitCode = 0;
|
||||
if (confirm("Do you really want to exit?")) {
|
||||
java.lang.System.exit(exitCode);
|
||||
}
|
||||
}
|
||||
exit.docString = "exits jconsole";
|
||||
|
||||
// synonym to exit
|
||||
var quit = exit;
|
||||
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file defines heapdump function to heap dump
|
||||
* in binary format. User can call this function
|
||||
* based on events. For example, a timer thread can
|
||||
* keep checking heap threshold and depending on
|
||||
* specific expected threshold value, it can call
|
||||
* heapdump to dump the keep. File name can contain
|
||||
* timestamp so that multiple heapdumps can be generated
|
||||
* for the same process.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function to dump heap in binary format.
|
||||
*
|
||||
* @param file heap dump file name [optional]
|
||||
*/
|
||||
function heapdump(file) {
|
||||
// no file specified, show file open dialog
|
||||
if (file == undefined) {
|
||||
file = fileDialog();
|
||||
// check whether user cancelled the dialog
|
||||
if (file == null) return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get HotSpotDiagnostic MBean and wrap it as convenient
|
||||
* script wrapper using 'mbean' function. Instead of using
|
||||
* MBean proxies 'mbean' function creates a script wrapper
|
||||
* that provides similar convenience but uses explicit
|
||||
* invocation behind the scene. This implies that mbean
|
||||
* wrapper would the same for dynamic MBeans as well.
|
||||
*/
|
||||
var diagBean = mbean("com.sun.management:type=HotSpotDiagnostic");
|
||||
|
||||
// dump the heap in the file
|
||||
diagBean.dumpHeap(file, true);
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This is sample JavaScript file that can be loaded into script console.
|
||||
* This file prints "hello, world".
|
||||
*/
|
||||
|
||||
echo("hello, world");
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This script demonstrates "invokeMBean" function. Instead
|
||||
* of using MXBean proxy or script wrapper object returned by
|
||||
* 'mbean' function, this file uses direct invoke on MBean.
|
||||
*
|
||||
* To use this particular script, load this script file in
|
||||
* script console prompt and call resetPeakThreadCount().
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resets the peak thread count to the current number of live threads.
|
||||
*
|
||||
*/
|
||||
function resetPeakThreadCount() {
|
||||
return invokeMBean("java.lang:type=Threading", "resetPeakThreadCount", [], {});
|
||||
}
|
||||
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file defines 'jstack' function to print stack traces of
|
||||
* threads.'jstack' function which can be called once or periodically
|
||||
* from a timer thread (calling it periodically would slow down the target
|
||||
* application). To call this once, just call 'jstack()' in script
|
||||
* console prompt. To call jstack in a timer thread, you can use
|
||||
*
|
||||
* var t = setInterval(function () { jstack(print); }, 5000);
|
||||
*
|
||||
* The above call prints threads in sorted order for every 5 seconds.
|
||||
* The print output goes to OS console window from which jconsole was
|
||||
* started. The timer can be cancelled later by clearTimeout() function
|
||||
* as shown below:
|
||||
*
|
||||
* clearInterval(t);
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* print given ThreadInfo using given printFunc
|
||||
*/
|
||||
function printThreadInfo(ti, printFunc) {
|
||||
printFunc(ti.threadId + " - " + ti.threadName + " - " + ti.threadState);
|
||||
var stackTrace = ti.stackTrace;
|
||||
for (var i in stackTrace) {
|
||||
printFunc("\t" + stackTrace[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* print stack traces of all threads.
|
||||
*
|
||||
* @param printFunc function called to print [optional]
|
||||
* @param maxFrames maximum number of frames to print [optional]
|
||||
*/
|
||||
function jstack(printFunc, maxFrames) {
|
||||
// by default use 'echo' to print. Other choices could be
|
||||
// 'print' or custom function that writes in a text file
|
||||
if (printFunc == undefined) {
|
||||
printFunc = echo;
|
||||
}
|
||||
|
||||
// by default print 25 frames
|
||||
if (maxFrames == undefined) {
|
||||
maxFrames = 25;
|
||||
}
|
||||
|
||||
var tmbean = newPlatformMXBeanProxy(
|
||||
"java.lang:type=Threading",
|
||||
java.lang.management.ThreadMXBean.class);
|
||||
|
||||
var tids = tmbean.allThreadIds;
|
||||
var tinfos = tmbean["getThreadInfo(long[],int)"](tids, maxFrames);
|
||||
|
||||
for (var i in tinfos) {
|
||||
printThreadInfo(tinfos[i], printFunc);
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This code is "ported" from JTop demo. This file defines
|
||||
* 'jtop' function. jtop prints threads sorting by CPU time.
|
||||
* jtop can be called once or periodically from a timer thread.
|
||||
* To call this once, just call 'jtop()' in script console prompt.
|
||||
* To call jtop in a timer thread, you can use
|
||||
*
|
||||
* var t = setInterval(function () { jtop(print); }, 2000);
|
||||
*
|
||||
* The above call prints threads in sorted order for every 2 seconds.
|
||||
* The print output goes to OS console window from which jconsole was
|
||||
* started. The timer can be cancelled later by clearTimeout() function
|
||||
* as shown below:
|
||||
*
|
||||
* clearInterval(t);
|
||||
*/
|
||||
|
||||
/**
|
||||
* This function returns a List of Map.Entry objects
|
||||
* in which each entry maps cpu time to ThreadInfo.
|
||||
*/
|
||||
function getThreadList() {
|
||||
var tmbean = newPlatformMXBeanProxy(
|
||||
"java.lang:type=Threading",
|
||||
java.lang.management.ThreadMXBean.class);
|
||||
|
||||
if (!tmbean.isThreadCpuTimeSupported()) {
|
||||
return java.util.Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
tmbean.setThreadCpuTimeEnabled(true);
|
||||
|
||||
var tids = tmbean.allThreadIds;
|
||||
var tinfos = tmbean["getThreadInfo(long[])"](tids);
|
||||
|
||||
var map = new java.util.TreeMap();
|
||||
for (var i in tids) {
|
||||
var cpuTime = tmbean.getThreadCpuTime(tids[i]);
|
||||
if (cpuTime != -1 && tinfos[i] != null) {
|
||||
map.put(cpuTime, tinfos[i]);
|
||||
}
|
||||
}
|
||||
var list = new java.util.ArrayList(map.entrySet());
|
||||
java.util.Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function prints threads sorted by CPU time.
|
||||
*
|
||||
* @param printFunc function called back to print [optional]
|
||||
*
|
||||
* By default, it uses 'echo' function to print in screen.
|
||||
* Other choices could be 'print' (prints in console), 'alert'
|
||||
* to show message box. Or you can define a function that writes
|
||||
* the output to a text file.
|
||||
*/
|
||||
function jtop(printFunc) {
|
||||
if (printFunc == undefined) {
|
||||
printFunc = echo;
|
||||
}
|
||||
var list = getThreadList();
|
||||
var itr = list.iterator();
|
||||
printFunc("time - state - name");
|
||||
while (itr.hasNext()) {
|
||||
var entry = itr.next();
|
||||
// time is in nanoseconds - convert to seconds
|
||||
var time = entry.key / 1.0e9;
|
||||
var name = entry.value.threadName;
|
||||
var state = entry.value.threadState;
|
||||
printFunc(time + " - " + state + " - " + name);
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file defines 'sysprops' function to print Java System
|
||||
* properties.'sysprops' function which can be called once or periodically
|
||||
* from a timer thread (calling it periodically would slow down the target
|
||||
* application). To call this once, just call 'sysprops()' in script
|
||||
* console prompt. To call sysprops in a timer thread, you can use
|
||||
*
|
||||
* var t = setInterval(function () { sysprops(print); }, 5000);
|
||||
*
|
||||
* The above call prints threads in sorted order for every 5 seconds.
|
||||
* The print output goes to OS console window from which jconsole was
|
||||
* started. The timer can be cancelled later by clearTimeout() function
|
||||
* as shown below:
|
||||
*
|
||||
* clearInterval(t);
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Returns System properties as a Map
|
||||
*/
|
||||
function getSystemProps() {
|
||||
var runtimeBean = newPlatformMXBeanProxy(
|
||||
"java.lang:type=Runtime",
|
||||
java.lang.management.RuntimeMXBean.class);
|
||||
return runtimeBean.systemProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* print System properties
|
||||
*
|
||||
* @param printFunc function called to print [optional]
|
||||
*/
|
||||
function sysprops(printFunc) {
|
||||
// by default use 'echo' to print. Other choices could be
|
||||
// 'print' or custom function that writes in a text file
|
||||
if (printFunc == undefined) {
|
||||
printFunc = echo;
|
||||
}
|
||||
|
||||
var map = getSystemProps();
|
||||
var keys = map.keySet().iterator();
|
||||
while (keys.hasNext()) {
|
||||
var key = keys.next();
|
||||
var value = map.get(key);
|
||||
printFunc(key + "=" + value);
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This script demonstrates "getMBeanAttribute"
|
||||
* and "setMBeanAttribute" functions. Instead of using
|
||||
* MXBean proxy or script wrapper object returned by
|
||||
* 'mbean' function, this file uses direct get/set MBean
|
||||
* attribute functions.
|
||||
*
|
||||
* To use this particular script, load this script file in
|
||||
* script console prompt and call verboseGC or verboseClass
|
||||
* functions. These functions based on events such as
|
||||
* heap threshold crossing a given limit. i.e., A timer thread
|
||||
* can keep checking for threshold event and then turn on
|
||||
* verbose:gc or verbose:class based on expected event.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get or set verbose GC flag.
|
||||
*
|
||||
* @param flag verbose mode flag [optional]
|
||||
*
|
||||
* If flag is not passed verboseGC returns current
|
||||
* flag value.
|
||||
*/
|
||||
function verboseGC(flag) {
|
||||
if (flag == undefined) {
|
||||
// no argument passed. interpret this as 'get'
|
||||
return getMBeanAttribute("java.lang:type=Memory", "Verbose");
|
||||
} else {
|
||||
return setMBeanAttribute("java.lang:type=Memory", "Verbose", flag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set verbose class flag.
|
||||
*
|
||||
* @param flag verbose mode flag [optional]
|
||||
*
|
||||
* If flag is not passed verboseClass returns current
|
||||
* flag value.
|
||||
*/
|
||||
function verboseClass(flag) {
|
||||
if (flag == undefined) {
|
||||
// no argument passed. interpret this as 'get'
|
||||
return getMBeanAttribute("java.lang:type=ClassLoading", "Verbose");
|
||||
} else {
|
||||
return setMBeanAttribute("java.lang:type=ClassLoading", "Verbose", flag);
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
import java.util.*;
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
|
||||
public class Client
|
||||
{
|
||||
private final static int BYTESPEROP= PollingServer.BYTESPEROP;
|
||||
private final static int PORTNUM = PollingServer.PORTNUM;
|
||||
private final static int MAXCONN = PollingServer.MAXCONN;
|
||||
|
||||
private static Socket[] sockArr = new Socket[MAXCONN];
|
||||
private static int totalConn =10;
|
||||
private static int bytesToSend =1024000;
|
||||
private static int connections = 0;
|
||||
private static int sends = 0;
|
||||
|
||||
public static void main (String args[]) {
|
||||
|
||||
String host = "localhost";
|
||||
|
||||
if (args.length < 1 || args.length > 3) {
|
||||
System.out.println("Usage : java Client <num_connects>");
|
||||
System.out.println(" | java Client <num_connects> <server_name>");
|
||||
System.out.println(" | java Client <num_connects> <server_name>" +
|
||||
" <max_Kbytes>");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
if (args.length >= 1)
|
||||
totalConn = java.lang.Integer.valueOf(args[0]).intValue();
|
||||
if (args.length >= 2)
|
||||
host = args[1];
|
||||
if (args.length == 3)
|
||||
bytesToSend = java.lang.Integer.valueOf(args[2]).intValue() * 1024;
|
||||
|
||||
|
||||
if (totalConn <= 0 || totalConn > MAXCONN) {
|
||||
System.out.println("Connections out of range. Terminating.");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
System.out.println("Using " + totalConn + " connections for sending " +
|
||||
bytesToSend + " bytes to " + host);
|
||||
|
||||
|
||||
try {
|
||||
Socket ctrlSock = new Socket (host, PORTNUM);
|
||||
PrintStream ctrlStream =
|
||||
new PrintStream(ctrlSock.getOutputStream());
|
||||
ctrlStream.println(bytesToSend);
|
||||
ctrlStream.println(totalConn);
|
||||
|
||||
while (connections < totalConn ) {
|
||||
sockArr[connections] = new Socket (host, PORTNUM);
|
||||
connections ++;
|
||||
}
|
||||
System.out.println("Connections made : " + connections);
|
||||
|
||||
byte[] buff = new byte[BYTESPEROP];
|
||||
for (int i = 0; i < BYTESPEROP; i++) // just put some junk in!
|
||||
buff[i] = (byte) i;
|
||||
|
||||
Random rand = new Random(5321L);
|
||||
while (sends < bytesToSend/BYTESPEROP) {
|
||||
int idx = java.lang.Math.abs(rand.nextInt()) % totalConn;
|
||||
sockArr[idx].getOutputStream().write(buff,0,BYTESPEROP);
|
||||
sends++;
|
||||
}
|
||||
// Wait for server to say done.
|
||||
int bytes = ctrlSock.getInputStream().read(buff, 0, BYTESPEROP);
|
||||
System.out.println (" Total connections : " + connections +
|
||||
" Bytes sent : " + sends * BYTESPEROP +
|
||||
"...Done!");
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
}
|
@ -1,230 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
File: SLQ.java
|
||||
Originally: LinkedQueue.java
|
||||
|
||||
Originally written by Doug Lea and released into the public domain.
|
||||
This may be used for any purposes whatsoever without acknowledgment.
|
||||
Thanks for the assistance and support of Sun Microsystems Labs,
|
||||
and everyone contributing, testing, and using this code.
|
||||
|
||||
History:
|
||||
Date Who What
|
||||
11Jun1998 dl Create public version
|
||||
25aug1998 dl added peek
|
||||
10dec1998 dl added isEmpty
|
||||
10jun1999 bc modified for isolated use
|
||||
*/
|
||||
|
||||
// Original was in package EDU.oswego.cs.dl.util.concurrent;
|
||||
|
||||
/**
|
||||
* A linked list based channel implementation,
|
||||
* adapted from the TwoLockQueue class from CPJ.
|
||||
* The algorithm avoids contention between puts
|
||||
* and takes when the queue is not empty.
|
||||
* Normally a put and a take can proceed simultaneously.
|
||||
* (Although it does not allow multiple concurrent puts or takes.)
|
||||
* This class tends to perform more efficently than
|
||||
* other Channel implementations in producer/consumer
|
||||
* applications.
|
||||
* <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
|
||||
**/
|
||||
|
||||
public class LinkedQueue {
|
||||
|
||||
|
||||
/**
|
||||
* Dummy header node of list. The first actual node, if it exists, is always
|
||||
* at head_.next. After each take, the old first node becomes the head.
|
||||
**/
|
||||
protected LinkedNode head_;
|
||||
protected int count_;
|
||||
/**
|
||||
* Helper monitor for managing access to last node, in case it is also first.
|
||||
* last_ and waitingForTake_ ONLY used with synch on appendMonitor_
|
||||
**/
|
||||
protected final Object lastMonitor_ = new Object();
|
||||
|
||||
/**
|
||||
* The last node of list. Put() appends to list, so modifies last_
|
||||
**/
|
||||
protected LinkedNode last_;
|
||||
|
||||
/**
|
||||
* The number of threads waiting for a take.
|
||||
* Notifications are provided in put only if greater than zero.
|
||||
* The bookkeeping is worth it here since in reasonably balanced
|
||||
* usages, the notifications will hardly ever be necessary, so
|
||||
* the call overhead to notify can be eliminated.
|
||||
**/
|
||||
protected int waitingForTake_ = 0;
|
||||
|
||||
public LinkedQueue() {
|
||||
head_ = new LinkedNode(null);
|
||||
last_ = head_;
|
||||
count_ = 0;
|
||||
}
|
||||
|
||||
/** Main mechanics for put/offer **/
|
||||
protected void insert(Object x) {
|
||||
synchronized(lastMonitor_) {
|
||||
LinkedNode p = new LinkedNode(x);
|
||||
last_.next = p;
|
||||
last_ = p;
|
||||
count_++;
|
||||
if (count_ > 1000 && (count_ % 1000 == 0))
|
||||
System.out.println("In Queue : " + count_);
|
||||
if (waitingForTake_ > 0)
|
||||
lastMonitor_.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/** Main mechanics for take/poll **/
|
||||
protected synchronized Object extract() {
|
||||
Object x = null;
|
||||
LinkedNode first = head_.next;
|
||||
if (first != null) {
|
||||
x = first.value;
|
||||
first.value = null;
|
||||
head_ = first;
|
||||
count_ --;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
public void put(Object x) throws InterruptedException {
|
||||
if (x == null) throw new IllegalArgumentException();
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
insert(x);
|
||||
}
|
||||
|
||||
public boolean offer(Object x, long msecs) throws InterruptedException {
|
||||
if (x == null) throw new IllegalArgumentException();
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
insert(x);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object take() throws InterruptedException {
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
// try to extract. If fail, then enter wait-based retry loop
|
||||
Object x = extract();
|
||||
if (x != null)
|
||||
return x;
|
||||
else {
|
||||
synchronized(lastMonitor_) {
|
||||
try {
|
||||
++waitingForTake_;
|
||||
for (;;) {
|
||||
x = extract();
|
||||
if (x != null) {
|
||||
--waitingForTake_;
|
||||
return x;
|
||||
}
|
||||
else {
|
||||
lastMonitor_.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(InterruptedException ex) {
|
||||
--waitingForTake_;
|
||||
lastMonitor_.notify();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Object peek() {
|
||||
LinkedNode first = head_.next;
|
||||
if (first != null)
|
||||
return first.value;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public synchronized boolean isEmpty() {
|
||||
return head_.next == null;
|
||||
}
|
||||
|
||||
public Object poll(long msecs) throws InterruptedException {
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
Object x = extract();
|
||||
if (x != null)
|
||||
return x;
|
||||
else {
|
||||
synchronized(lastMonitor_) {
|
||||
try {
|
||||
long waitTime = msecs;
|
||||
long start = (msecs <= 0)? 0 : System.currentTimeMillis();
|
||||
++waitingForTake_;
|
||||
for (;;) {
|
||||
x = extract();
|
||||
if (x != null || waitTime <= 0) {
|
||||
--waitingForTake_;
|
||||
return x;
|
||||
}
|
||||
else {
|
||||
lastMonitor_.wait(waitTime);
|
||||
waitTime = msecs - (System.currentTimeMillis() - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(InterruptedException ex) {
|
||||
--waitingForTake_;
|
||||
lastMonitor_.notify();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LinkedNode {
|
||||
Object value;
|
||||
LinkedNode next = null;
|
||||
LinkedNode(Object x) { value = x; }
|
||||
LinkedNode(Object x, LinkedNode n) { value = x; next = n; }
|
||||
}
|
||||
}
|
@ -1,753 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
* Poller.c :
|
||||
* JNI code for use with Poller.java, principally to take advantage
|
||||
* of poll() or /dev/poll multiplexing.
|
||||
*
|
||||
* One will need Solaris 8 or Solaris 7 with adequate patches to take
|
||||
* advantage of the /dev/poll performance enhancements, though any
|
||||
* version of Solaris 7 will automatically use the kernel poll()
|
||||
* caching. And poll() will function in 2.5.1 and 2.6 as well, but
|
||||
* will not perform well for large numbers of file descriptors.
|
||||
*
|
||||
* Several assumptions have been made to simplify this code :
|
||||
* 1> At most MAX_HANDLES (32) separate pollable entities are currently
|
||||
* supported.
|
||||
* 2> Global synchronization from Java is assumed for all init, create
|
||||
* and destroy routines. Per Object (handle passed in) synchronization
|
||||
* is required for all AddFd, RemoveFd, IsMember, and Wait routines.
|
||||
* 3> It is currently up to the user to handle waking up an
|
||||
* existing nativeWait() call to do an addfd or removefd on
|
||||
* that set...could implement that here with an extra pipe, or
|
||||
* with a pair of loopback sockets in Poller.java or user code.
|
||||
* In most cases interruption is not necessary for deletions,
|
||||
* so long as deletions are queued up outside the Poller class
|
||||
* and then executed the next time waitMultiple() returns.
|
||||
* 4> /dev/poll performance could be slightly improved by coalescing
|
||||
* adds/removes so that a write() is only done before the ioctl
|
||||
* (DP_POLL), but this complicates exception handling and sees
|
||||
* only modest performance gains so wasn't done.
|
||||
* 5> /dev/poll does not report errors on attempts to remove non-
|
||||
* extant fds, but a future bug fix to the /dev/poll device driver
|
||||
* should solve this problem.
|
||||
* 6> Could add simpler code for pre-Solaris 7 releases which will
|
||||
* perform slightly better on those OSs. But again there
|
||||
* are only modest gains to be had from these new code paths,
|
||||
* so they've been omitted here.
|
||||
*
|
||||
* Compile "cc -G -o <dest_dir>/libpoller.so -I ${JAVA_HOME}/include " \
|
||||
* -I ${JAVA_HOME}/include/solaris Poller.c" and place the <dest_dir>
|
||||
* in your LD_LIBRARY_PATH
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <malloc.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
/*
|
||||
* Remove "_NOT"s to turn on features
|
||||
* Append "_NOT" to turn off features.
|
||||
* Use of /dev/poll requires both the include file and kernel driver.
|
||||
*/
|
||||
#define DEBUG_NOT
|
||||
#define DEVPOLL_NOT
|
||||
|
||||
#ifdef DEVPOLL
|
||||
#include <sys/devpoll.h>
|
||||
#endif
|
||||
|
||||
#include "Poller.h"
|
||||
|
||||
#define MAX_HANDLES 32
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBGMSG(x) printf x
|
||||
#define ASSERT(x) {if (!(x)) \
|
||||
printf("assertion(%s) failed at line : %d\n",#x,__LINE__);}
|
||||
#define CHECK_HANDLE(x) check_handle(x)
|
||||
#else
|
||||
#define DBGMSG(x)
|
||||
#define ASSERT(x)
|
||||
#define CHECK_HANDLE(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Globals ...protect all with a global synchronization object.
|
||||
*/
|
||||
|
||||
static int Current_handle = 0;
|
||||
static int Use_devpoll = 0;
|
||||
static int Max_index = 0;
|
||||
|
||||
/*
|
||||
* Per Poller object data.
|
||||
* Must be synchronized on a per Poller object basis.
|
||||
*/
|
||||
|
||||
typedef struct ioevent {
|
||||
int inuse;
|
||||
int devpollfd;
|
||||
int last_index;
|
||||
int total_free;
|
||||
int left_events;
|
||||
int max_index;
|
||||
pollfd_t *pfd;
|
||||
} ioevent_t;
|
||||
|
||||
static ioevent_t IOE_handles[MAX_HANDLES];
|
||||
|
||||
/*
|
||||
* Exceptions to be thrown.
|
||||
* Note : assuming all illegal argument and NULL pointer checks
|
||||
* have already been done by the Java calling methods.
|
||||
*/
|
||||
static jint throwOutOfMemoryError(JNIEnv *env, const char * cause)
|
||||
{
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env,"java/lang/OutOfMemoryError"),
|
||||
cause);
|
||||
return -1;
|
||||
}
|
||||
static jint throwInterruptedIOException(JNIEnv *env, const char * cause)
|
||||
{
|
||||
(*env)->ThrowNew(env,
|
||||
(*env)->FindClass(env,"java/io/InterruptedIOException"),
|
||||
cause);
|
||||
return -1;
|
||||
}
|
||||
static jint throwIllegalStateException(JNIEnv *env, const char * cause)
|
||||
{
|
||||
(*env)->ThrowNew(env,
|
||||
(*env)->FindClass(env,"java/lang/IllegalStateException"),
|
||||
cause);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define MEMORY_EXCEPTION(str) throwOutOfMemoryError(env, "Poller:" str)
|
||||
#define STATE_EXCEPTION(str) throwIllegalStateException(env, "Poller:" str)
|
||||
#define INTERRUPT_EXCEPTION(str) throwInterruptedIOException(env, \
|
||||
"Poller:" str)
|
||||
jint addfd(JNIEnv *, ioevent_t *, jint, jshort);
|
||||
jint removefd(JNIEnv *, ioevent_t *, jint);
|
||||
|
||||
/*
|
||||
* Class Poller
|
||||
* Method: nativeInit
|
||||
* Signature: ()I
|
||||
*
|
||||
* Only to be called once, right after this library is loaded,
|
||||
* so no need to deal with reentrancy here.
|
||||
* Could do as a pragma ini, but that isn't as portable.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_Poller_nativeInit(JNIEnv *env, jclass cls)
|
||||
{
|
||||
int testdevpollfd;
|
||||
int i;
|
||||
|
||||
#ifdef DEVPOLL
|
||||
/*
|
||||
* See if we can use this much faster method
|
||||
* Note : must have fix for BUGID # 4223353 or OS can crash!
|
||||
*/
|
||||
testdevpollfd = open("/dev/poll",O_RDWR);
|
||||
if (testdevpollfd >= 0) {
|
||||
/*
|
||||
* If Solaris 7, we need a patch
|
||||
* Until we know what string to search for, we'll play it
|
||||
* safe and disable this for Solaris 7.
|
||||
*/
|
||||
|
||||
if (!strcmp(name.release,"5.7"))
|
||||
{
|
||||
Use_devpoll = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Use_devpoll = 1;
|
||||
}
|
||||
}
|
||||
|
||||
DBGMSG(("Use_devpoll=%d\n" ,Use_devpoll));
|
||||
close(testdevpollfd);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For now, we optimize for Solaris 7 if /dev/poll isn't
|
||||
* available, as it is only a small % hit for Solaris < 7.
|
||||
* if ( (Use_devpoll == 0) && !strcmp(name.release,"5.6") )
|
||||
* Use_sol7opt = 0;
|
||||
*/
|
||||
Current_handle = 0;
|
||||
for (i = 0; i < MAX_HANDLES; i++) {
|
||||
IOE_handles[i].devpollfd = -1;
|
||||
IOE_handles[i].pfd = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* this tells me the max number of open filedescriptors
|
||||
*/
|
||||
Max_index = sysconf(_SC_OPEN_MAX);
|
||||
if (Max_index < 0) {
|
||||
Max_index = 1024;
|
||||
}
|
||||
|
||||
DBGMSG(("got sysconf(_SC_OPEN_MAX)=%d file desc\n",Max_index));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_Poller_getNumCPUs(JNIEnv *env, jclass cls)
|
||||
{
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: Poller
|
||||
* Method: nativeCreatePoller
|
||||
* Signature: (I)I
|
||||
* Note : in the case where /dev/poll doesn't exist,
|
||||
* using more than one poll array could hurt
|
||||
* Solaris 7 performance due to kernel caching.
|
||||
*/
|
||||
|
||||
JNIEXPORT jint JNICALL Java_Poller_nativeCreatePoller
|
||||
(JNIEnv *env, jobject obj, jint maximum_fds)
|
||||
{
|
||||
int handle, retval, i;
|
||||
ioevent_t *ioeh;
|
||||
|
||||
if (maximum_fds == -1) {
|
||||
maximum_fds = Max_index;
|
||||
}
|
||||
handle = Current_handle;
|
||||
if (Current_handle >= MAX_HANDLES) {
|
||||
for (i = 0; i < MAX_HANDLES; i++) {
|
||||
if (IOE_handles[i].inuse == 0) {
|
||||
handle = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (handle >= MAX_HANDLES) {
|
||||
return MEMORY_EXCEPTION("CreatePoller - MAX_HANDLES exceeded");
|
||||
}
|
||||
} else {
|
||||
Current_handle++;
|
||||
}
|
||||
|
||||
ioeh = &IOE_handles[handle];
|
||||
|
||||
ioeh->inuse = 1;
|
||||
|
||||
ioeh->last_index = 0;
|
||||
ioeh->total_free = 0;
|
||||
ioeh->left_events = 0;
|
||||
ioeh->max_index = maximum_fds;
|
||||
|
||||
retval = handle;
|
||||
if (Use_devpoll) {
|
||||
ioeh->devpollfd = open("/dev/poll",O_RDWR);
|
||||
DBGMSG(("Opened /dev/poll, set devpollfd = %d\n",ioeh->devpollfd));
|
||||
if (ioeh->devpollfd < 0) {
|
||||
Current_handle--;
|
||||
return MEMORY_EXCEPTION("CreatePoller - can\'t open /dev/poll");
|
||||
}
|
||||
}
|
||||
ioeh->pfd = malloc(maximum_fds * sizeof(pollfd_t));
|
||||
if (ioeh->pfd == NULL) {
|
||||
Current_handle--;
|
||||
return MEMORY_EXCEPTION("CreatePoller - malloc failure");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: Poller
|
||||
* Method: nativeDestroyPoller
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_Poller_nativeDestroyPoller
|
||||
(JNIEnv *env, jobject obj, jint handle)
|
||||
{
|
||||
|
||||
ioevent_t *ioeh;
|
||||
|
||||
if (handle < 0 || handle >= MAX_HANDLES)
|
||||
{
|
||||
STATE_EXCEPTION("DestroyPoller - handle out of range");
|
||||
return;
|
||||
}
|
||||
|
||||
ioeh = &IOE_handles[handle];
|
||||
ioeh->inuse = 0;
|
||||
if (Use_devpoll) {
|
||||
close(ioeh->devpollfd);
|
||||
}
|
||||
free(ioeh->pfd);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void check_handle(ioevent_t *ioeh)
|
||||
{
|
||||
int i,used,unused;
|
||||
|
||||
used=unused=0;
|
||||
for (i = 0; i < ioeh->last_index; i++)
|
||||
{
|
||||
if (ioeh->pfd[i].fd == -1)
|
||||
unused++;
|
||||
else
|
||||
used++;
|
||||
}
|
||||
if (unused != ioeh->total_free)
|
||||
printf("WARNING : found %d free, claimed %d. Used : %d\n",
|
||||
unused, ioeh->total_free, used);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Class: Poller
|
||||
* Method: nativeAddFd
|
||||
* Signature: (IIS)I
|
||||
*
|
||||
* Currently doesn't check to make sure we aren't adding
|
||||
* an fd already added (no problem for /dev/poll...just
|
||||
* an array waster for poll()).
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_Poller_nativeAddFd
|
||||
(JNIEnv *env, jobject obj, jint handle, jint fd, jshort events)
|
||||
{
|
||||
int retval;
|
||||
ioevent_t *ioeh;
|
||||
|
||||
if (handle < 0 || handle >= MAX_HANDLES)
|
||||
return STATE_EXCEPTION("AddFd - handle out of range");
|
||||
|
||||
ioeh = &IOE_handles[handle];
|
||||
|
||||
CHECK_HANDLE(ioeh);
|
||||
|
||||
#ifdef DEVPOLL
|
||||
if (Use_devpoll)
|
||||
{
|
||||
int i;
|
||||
pollfd_t pollelt;
|
||||
|
||||
/*
|
||||
* use /dev/poll
|
||||
*/
|
||||
pollelt.fd = fd;
|
||||
pollelt.events = events;
|
||||
if ((i = write(ioeh->devpollfd, &pollelt, sizeof(pollfd_t))) !=
|
||||
sizeof(pollfd_t)) {
|
||||
DBGMSG(("write to devpollfd=%d showed %d bytes out of %d\n",
|
||||
ioeh->devpollfd,i,sizeof(pollfd_t)));
|
||||
return STATE_EXCEPTION("AddFd - /dev/poll add failure");
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = fd;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{ /* no /dev/poll available */
|
||||
retval = addfd(env, ioeh, fd, events);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Addfd to pollfd array...optimized for Solaris 7
|
||||
*/
|
||||
jint addfd(JNIEnv *env, ioevent_t *ioeh, jint fd, jshort events)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (ioeh->total_free)
|
||||
{
|
||||
/*
|
||||
* Traversing from end because that's where we pad.
|
||||
*/
|
||||
ioeh->total_free--;
|
||||
for (idx = ioeh->last_index - 1; idx >= 0; idx--) {
|
||||
if (ioeh->pfd[idx].fd == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ioeh->last_index >= ioeh->max_index)
|
||||
{
|
||||
return MEMORY_EXCEPTION("AddFd - too many fds");
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
int new_total;
|
||||
/*
|
||||
* For Solaris 7, want to add some growth space
|
||||
* and fill extras with fd=-1. This allows for
|
||||
* kernel poll() implementation to perform optimally.
|
||||
*/
|
||||
new_total = ioeh->last_index;
|
||||
new_total += (new_total/10) + 1; /* bump size by 10% */
|
||||
if (new_total > ioeh->max_index)
|
||||
new_total = ioeh->max_index;
|
||||
for (i = ioeh->last_index; i <= new_total; i++)
|
||||
{
|
||||
ioeh->pfd[i].fd = -1;
|
||||
}
|
||||
idx = ioeh->last_index;
|
||||
ioeh->total_free = new_total - ioeh->last_index - 1;
|
||||
DBGMSG(("Just grew from %d to %d in size\n",
|
||||
ioeh->last_index, new_total));
|
||||
ioeh->last_index = new_total;
|
||||
}
|
||||
ASSERT((idx >= 0) && (idx <= ioeh->max_index));
|
||||
ASSERT(ioeh->pfd[idx].fd == -1);
|
||||
ioeh->pfd[idx].fd = fd;
|
||||
ioeh->pfd[idx].events = events;
|
||||
ioeh->pfd[idx].revents = 0;
|
||||
|
||||
CHECK_HANDLE(ioeh);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: Poller
|
||||
* Method: nativeRemoveFd
|
||||
* Signature: (II)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_Poller_nativeRemoveFd
|
||||
(JNIEnv *env, jobject obj, jint handle, jint fd)
|
||||
{
|
||||
ioevent_t *ioeh;
|
||||
|
||||
if (handle < 0 || handle >= MAX_HANDLES)
|
||||
return STATE_EXCEPTION("RemoveFd - handle out of range");
|
||||
|
||||
ioeh = &IOE_handles[handle];
|
||||
|
||||
#ifdef DEVPOLL
|
||||
if (Use_devpoll)
|
||||
{
|
||||
/*
|
||||
* use /dev/poll - currently no need for locking here.
|
||||
*/
|
||||
pollfd_t pollelt;
|
||||
|
||||
pollelt.fd = fd;
|
||||
pollelt.events = POLLREMOVE;
|
||||
if (write(ioeh->devpollfd, &pollelt,
|
||||
sizeof(pollfd_t) ) != sizeof(pollfd_t))
|
||||
{
|
||||
return STATE_EXCEPTION("RemoveFd - /dev/poll failure");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif DEVPOLL
|
||||
{
|
||||
return removefd(env, ioeh,fd);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* remove from pollfd array...optimize for Solaris 7
|
||||
*/
|
||||
jint removefd(JNIEnv *env, ioevent_t *ioeh, jint fd)
|
||||
{
|
||||
int i;
|
||||
int found = 0;
|
||||
|
||||
{ /* !Use_devpoll */
|
||||
for (i = 0; i < ioeh->last_index; i++)
|
||||
{
|
||||
if (ioeh->pfd[i].fd == fd)
|
||||
{
|
||||
ioeh->pfd[i].fd = -1;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
return STATE_EXCEPTION("RemoveFd - no such fd");
|
||||
}
|
||||
ioeh->left_events = 0; /* Have to go back to the kernel */
|
||||
ioeh->total_free++;
|
||||
/*
|
||||
* Shrinking pool if > 33% empty. Just don't do this often!
|
||||
*/
|
||||
if ( (ioeh->last_index > 100) &&
|
||||
(ioeh->total_free > (ioeh->last_index / 3)) )
|
||||
{
|
||||
int j;
|
||||
/*
|
||||
* we'll just bite the bullet here, since we're > 33% empty.
|
||||
* walk through and eliminate -1 fd values, shrink total
|
||||
* size to still have ~ 10 fd==-1 values at end.
|
||||
* Start at end (since we pad here) and, when we find fd != -1,
|
||||
* swap with an earlier fd == -1 until we have all -1 values
|
||||
* at the end.
|
||||
*/
|
||||
CHECK_HANDLE(ioeh);
|
||||
for (i = ioeh->last_index - 1, j = 0; i > j; i--)
|
||||
{
|
||||
if (ioeh->pfd[i].fd != -1)
|
||||
{
|
||||
while ( (j < i) && (ioeh->pfd[j].fd != -1) )
|
||||
j++;
|
||||
DBGMSG( ("i=%d,j=%d,ioeh->pfd[j].fd=%d\n",
|
||||
i, j, ioeh->pfd[j].fd) );
|
||||
if (j < i)
|
||||
{
|
||||
ASSERT(ioeh->pfd[j].fd == -1);
|
||||
ioeh->pfd[j].fd = ioeh->pfd[i].fd;
|
||||
ioeh->pfd[j].events = ioeh->pfd[i].events;
|
||||
ioeh->pfd[i].fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
DBGMSG(("Just shrunk from %d to %d in size\n",
|
||||
ioeh->last_index, j+11));
|
||||
ioeh->last_index = j + 11; /* last_index always 1 greater */
|
||||
ioeh->total_free = 10;
|
||||
CHECK_HANDLE(ioeh);
|
||||
}
|
||||
} /* !Use_devpoll */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: Poller
|
||||
* Method: nativeIsMember
|
||||
* Signature: (II)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_Poller_nativeIsMember
|
||||
(JNIEnv *env, jobject obj, jint handle, jint fd)
|
||||
{
|
||||
int found = 0;
|
||||
int i;
|
||||
ioevent_t *ioeh;
|
||||
|
||||
if (handle < 0 || handle >= MAX_HANDLES)
|
||||
return STATE_EXCEPTION("IsMember - handle out of range");
|
||||
|
||||
ioeh = &IOE_handles[handle];
|
||||
|
||||
#ifdef DEVPOLL
|
||||
if (Use_devpoll)
|
||||
{
|
||||
pollfd_t pfd;
|
||||
/*
|
||||
* DEVPOLL ioctl DP_ISPOLLED call to determine if fd is polled.
|
||||
*/
|
||||
pfd.fd = fd;
|
||||
pfd.events = 0;
|
||||
pfd.revents = 0;
|
||||
found = ioctl(ioeh->devpollfd, DP_ISPOLLED, &pfd);
|
||||
if (found == -1)
|
||||
{
|
||||
return STATE_EXCEPTION("IsMember - /dev/poll failure");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for (i = 0; i < ioeh->last_index; i++)
|
||||
{
|
||||
if (fd == ioeh->pfd[i].fd)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: Poller
|
||||
* Method: nativeWait
|
||||
* Signature: (II[I[SJ)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_Poller_nativeWait
|
||||
(JNIEnv *env, jobject obj, jint handle, jint maxEvents,
|
||||
jintArray jfds, jshortArray jrevents, jlong timeout)
|
||||
{
|
||||
int useEvents, count, idx;
|
||||
short *reventp;
|
||||
jint *fdp;
|
||||
int retval;
|
||||
ioevent_t *ioeh;
|
||||
jboolean isCopy1,isCopy2;
|
||||
|
||||
if (handle < 0 || handle >= MAX_HANDLES)
|
||||
return STATE_EXCEPTION("nativeWait - handle out of range");
|
||||
|
||||
ioeh = &IOE_handles[handle];
|
||||
|
||||
if (maxEvents == 0) /* just doing a kernel delay! */
|
||||
{
|
||||
useEvents = poll(NULL,0L,timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEVPOLL
|
||||
if (Use_devpoll)
|
||||
{
|
||||
struct dvpoll dopoll;
|
||||
/*
|
||||
* DEVPOLL ioctl DP_POLL call, reading
|
||||
*/
|
||||
dopoll.dp_timeout = timeout;
|
||||
dopoll.dp_nfds=maxEvents;
|
||||
dopoll.dp_fds=ioeh->pfd;
|
||||
|
||||
useEvents = ioctl(ioeh->devpollfd, DP_POLL, &dopoll);
|
||||
while ((useEvents == -1) && (errno == EAGAIN))
|
||||
useEvents = ioctl(ioeh->devpollfd, DP_POLL, &dopoll);
|
||||
|
||||
if (useEvents == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
return INTERRUPT_EXCEPTION("nativeWait - /dev/poll failure EINTR");
|
||||
else
|
||||
return STATE_EXCEPTION("nativeWait - /dev/poll failure");
|
||||
}
|
||||
|
||||
reventp =(*env)->GetShortArrayElements(env,jrevents,&isCopy1);
|
||||
fdp =(*env)->GetIntArrayElements(env,jfds,&isCopy2);
|
||||
for (idx = 0,count = 0; idx < useEvents; idx++)
|
||||
{
|
||||
if (ioeh->pfd[idx].revents)
|
||||
{
|
||||
fdp[count] = ioeh->pfd[idx].fd;
|
||||
reventp[count] = ioeh->pfd[idx].revents;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count < useEvents)
|
||||
return STATE_EXCEPTION("Wait - Corrupted internals");
|
||||
|
||||
if (isCopy1 == JNI_TRUE)
|
||||
(*env)->ReleaseShortArrayElements(env,jrevents,reventp,0);
|
||||
if (isCopy2 == JNI_TRUE)
|
||||
(*env)->ReleaseIntArrayElements(env,jfds,fdp,0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{ /* !Use_devpoll */
|
||||
|
||||
/* no leftovers=>go to kernel */
|
||||
if (ioeh->left_events == 0)
|
||||
{
|
||||
useEvents = poll(ioeh->pfd,ioeh->last_index, timeout);
|
||||
while ((useEvents == -1) && (errno == EAGAIN))
|
||||
useEvents = poll(ioeh->pfd,ioeh->last_index, timeout);
|
||||
if (useEvents == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
return INTERRUPT_EXCEPTION("Wait - poll() failure EINTR-" \
|
||||
"IO interrupted.");
|
||||
else if (errno == EINVAL)
|
||||
return STATE_EXCEPTION("Wait - poll() failure EINVAL-" \
|
||||
"invalid args (is fdlim cur < max?)");
|
||||
else
|
||||
return STATE_EXCEPTION("Wait - poll() failure");
|
||||
}
|
||||
ioeh->left_events = useEvents;
|
||||
DBGMSG(("waitnative : poll returns : %d\n",useEvents));
|
||||
}
|
||||
else
|
||||
{ /* left over from last call */
|
||||
useEvents = ioeh->left_events;
|
||||
}
|
||||
|
||||
if (useEvents > maxEvents)
|
||||
{
|
||||
useEvents = maxEvents;
|
||||
}
|
||||
|
||||
ioeh->left_events -= useEvents; /* left to process */
|
||||
|
||||
DBGMSG(("waitnative : left %d, use %d, max %d\n",ioeh->left_events,
|
||||
useEvents,maxEvents));
|
||||
|
||||
if (useEvents > 0)
|
||||
{
|
||||
reventp =(*env)->GetShortArrayElements(env,jrevents,&isCopy1);
|
||||
fdp =(*env)->GetIntArrayElements(env,jfds,&isCopy2);
|
||||
for (idx = 0,count = 0; (idx < ioeh->last_index) &&
|
||||
(count < useEvents); idx++)
|
||||
{
|
||||
if (ioeh->pfd[idx].revents)
|
||||
{
|
||||
fdp[count] = ioeh->pfd[idx].fd;
|
||||
reventp[count] = ioeh->pfd[idx].revents;
|
||||
/* in case of leftover for next walk */
|
||||
ioeh->pfd[idx].revents = 0;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count < useEvents)
|
||||
{
|
||||
ioeh->left_events = 0;
|
||||
return STATE_EXCEPTION("Wait - Corrupted internals");
|
||||
}
|
||||
if (isCopy1 == JNI_TRUE)
|
||||
(*env)->ReleaseShortArrayElements(env,jrevents,reventp,0);
|
||||
if (isCopy2 == JNI_TRUE)
|
||||
(*env)->ReleaseIntArrayElements(env,jfds,fdp,0);
|
||||
}
|
||||
} /* !Use_devpoll */
|
||||
|
||||
return useEvents;
|
||||
}
|
@ -1,335 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* This class is provided for access to the underlying poll(2)
|
||||
* or /dev/poll kernel interfaces. This may be needed for
|
||||
* multiplexing IO when an application cannot afford to have
|
||||
* a thread block on each outstanding IO request.
|
||||
*
|
||||
* It currently supports the same basic functionality as the
|
||||
* C poll(2) API, although for efficiency we needed to avoid
|
||||
* passing the entire pollfd array for every call. See man
|
||||
* pages for poll(2) for info on C API and event types.
|
||||
*
|
||||
*
|
||||
* @author Bruce Chapman
|
||||
* @see java.io.FileDescriptor
|
||||
* @see java.net.Socket
|
||||
* @see attached README.txt
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class Poller {
|
||||
/**
|
||||
* Solaris POLL event types.
|
||||
*/
|
||||
public final static short POLLERR = 0x08;
|
||||
public final static short POLLHUP = 0x10;
|
||||
public final static short POLLNVAL = 0x20;
|
||||
public final static short POLLIN = 1;
|
||||
public final static short POLLPRI = 2;
|
||||
public final static short POLLOUT = 4;
|
||||
public final static short POLLRDNORM = 0x40;
|
||||
public final static short POLLWRNORM = POLLOUT ;
|
||||
public final static short POLLRDBAND = 0x80;
|
||||
public final static short POLLWRBAND = 0x100;
|
||||
public final static short POLLNORM = POLLRDNORM;
|
||||
|
||||
/*
|
||||
* This global synchronization object must be used for all
|
||||
* creation or destruction of Poller objects.
|
||||
*/
|
||||
private final static Object globalSync = new Object();
|
||||
|
||||
/*
|
||||
* The handle for a Poller Object...is used in the JNI C code
|
||||
* where all the associated data is kept.
|
||||
*/
|
||||
private int handle;
|
||||
|
||||
/**
|
||||
* Constructs an instance of a <code>Poller</code> object.
|
||||
* Native code uses sysconf(_SC_OPEN_MAX) to determine how
|
||||
* many fd/skt objects this Poller object can contain.
|
||||
*/
|
||||
public Poller() throws Exception {
|
||||
synchronized(globalSync) {
|
||||
this.handle = nativeCreatePoller(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of a <code>Poller</code> object.
|
||||
* @param maxFd the maximum number of FileDescriptors/Sockets
|
||||
* this Poller object can contain.
|
||||
*/
|
||||
public Poller(int maxFd) throws Exception {
|
||||
synchronized(globalSync) {
|
||||
this.handle = nativeCreatePoller(maxFd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Needed to clean up at the JNI C level when object is GCd.
|
||||
*/
|
||||
protected void finalize() throws Throwable {
|
||||
synchronized(globalSync) {
|
||||
nativeDestroyPoller(handle);
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we can't guarantee WHEN finalize is called, we may
|
||||
* recycle on our own.
|
||||
* @param maxFd the maximum number of FileDescriptors/Sockets
|
||||
* this Poller object can contain.
|
||||
*/
|
||||
public void reset(int maxFd) throws Exception {
|
||||
synchronized(globalSync) {
|
||||
nativeDestroyPoller(handle);
|
||||
this.handle = nativeCreatePoller(maxFd);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Since we can't guarantee WHEN finalize is called, we may
|
||||
* recycle on our own.
|
||||
*/
|
||||
public void reset() throws Exception {
|
||||
synchronized(globalSync) {
|
||||
nativeDestroyPoller(handle);
|
||||
this.handle = nativeCreatePoller(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add FileDescriptor to the set handled by this Poller object.
|
||||
*
|
||||
* @param fdObj the FileDescriptor, Socket, or ServerSocket to add.
|
||||
* @param event the bitmask of events we are interested in.
|
||||
* @return the OS level fd associated with this IO Object
|
||||
* (which is what waitMultiple() stores in fds[])
|
||||
*/
|
||||
public synchronized int add(Object fdObj, short event) throws Exception {
|
||||
return nativeAddFd(handle,findfd(fdObj), event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove FileDescriptor from the set handled by this Poller object.
|
||||
*
|
||||
* Must be called before the fd/skt is closed.
|
||||
* @param fdObj the FileDescriptor, Socket, or ServerSocket to remove.
|
||||
* @return true if removal succeeded.
|
||||
*/
|
||||
public synchronized boolean remove(Object fdObj) throws Exception {
|
||||
return (nativeRemoveFd(handle,findfd(fdObj)) == 1);
|
||||
}
|
||||
/**
|
||||
* Check if fd or socket is already in the set handled by this Poller object
|
||||
*
|
||||
* @param fdObj the FileDescriptor or [Server]Socket to check.
|
||||
* @return true if fd/skt is in the set for this Poller object.
|
||||
*/
|
||||
public synchronized boolean isMember(Object fdObj) throws Exception {
|
||||
return (nativeIsMember(handle,findfd(fdObj)) == 1);
|
||||
}
|
||||
/**
|
||||
* Wait on Multiple IO Objects.
|
||||
*
|
||||
* @param maxRet the maximum number of fds[] and revents[] to return.
|
||||
* @param fds[] (return) an array of ints in which to store fds with
|
||||
* available data upon a successful non-timeout return.
|
||||
* fds.length must be >= maxRet
|
||||
* @param revents[] (return) the actual events available on the
|
||||
* same-indexed fds[] (i.e. fds[0] has events revents[0])
|
||||
* revents.length must be >= maxRet
|
||||
*
|
||||
* Note : both above arrays are "dense," i.e. only fds[] with events
|
||||
* available are returned.
|
||||
*
|
||||
* @param timeout the maximum number of milliseconds to wait for
|
||||
* events before timing out.
|
||||
* @return the number of fds with triggered events.
|
||||
*
|
||||
* Note : convenience methods exist for skipping the timeout parameter
|
||||
* or the maxRet parameter (in the case of no maxRet, fds.length
|
||||
* must equal revents.length)
|
||||
*
|
||||
* obj.waitMultiple(null,null,timeout) can be used for pausing the LWP
|
||||
* (much more reliable and scalable than Thread.sleep() or Object.wait())
|
||||
*/
|
||||
public synchronized int waitMultiple(int maxRet, int[] fds,short[] revents,
|
||||
long timeout) throws Exception
|
||||
{
|
||||
if ((revents == null) || (fds == null)) {
|
||||
if (maxRet > 0) {
|
||||
throw new NullPointerException("fds or revents is null");
|
||||
}
|
||||
} else if ( (maxRet < 0) ||
|
||||
(maxRet > revents.length) || (maxRet > fds.length) ) {
|
||||
throw new IllegalArgumentException("maxRet out of range");
|
||||
}
|
||||
|
||||
int ret = nativeWait(handle, maxRet, fds, revents, timeout);
|
||||
if (ret < 0) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait on Multiple IO Objects (no timeout).
|
||||
* A convenience method for waiting indefinitely on IO events
|
||||
*
|
||||
* @see Poller#waitMultiple
|
||||
*
|
||||
*/
|
||||
public int waitMultiple(int maxRet, int[] fds, short[] revents)
|
||||
throws Exception
|
||||
{
|
||||
return waitMultiple(maxRet, fds, revents,-1L); // already synchronized
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait on Multiple IO Objects (no maxRet).
|
||||
* A convenience method for waiting on IO events when the fds
|
||||
* and revents arrays are the same length and that specifies the
|
||||
* maximum number of return events.
|
||||
*
|
||||
* @see Poller#waitMultiple
|
||||
*
|
||||
*/
|
||||
public synchronized int waitMultiple(int[] fds, short[] revents,
|
||||
long timeout) throws Exception
|
||||
{
|
||||
if ((revents == null) && (fds == null)) {
|
||||
return nativeWait(handle,0,null,null,timeout);
|
||||
} else if ((revents == null) || (fds == null)) {
|
||||
throw new NullPointerException("revents or fds is null");
|
||||
} else if (fds.length == revents.length) {
|
||||
return nativeWait(handle, fds.length, fds, revents, timeout);
|
||||
}
|
||||
throw new IllegalArgumentException("fds.length != revents.length");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wait on Multiple IO Objects (no maxRet/timeout).
|
||||
* A convenience method for waiting on IO events when the fds
|
||||
* and revents arrays are the same length and that specifies the
|
||||
* maximum number of return events, and when waiting indefinitely
|
||||
* for IO events to occur.
|
||||
*
|
||||
* @see Poller#waitMultiple
|
||||
*
|
||||
*/
|
||||
public int waitMultiple(int[] fds, short[] revents)
|
||||
throws Exception
|
||||
{
|
||||
if ((revents == null) || (fds == null)) {
|
||||
throw new NullPointerException("fds or revents is null");
|
||||
} else if (fds.length == revents.length) {
|
||||
return waitMultiple(revents.length,fds,revents,-1L); // already sync
|
||||
}
|
||||
throw new IllegalArgumentException("fds.length != revents.length");
|
||||
}
|
||||
|
||||
// Utility - get (int) fd from FileDescriptor or [Server]Socket objects.
|
||||
|
||||
private int findfd(Object fdObj) throws Exception {
|
||||
Class cl;
|
||||
Field f;
|
||||
Object val, implVal;
|
||||
|
||||
if ((fdObj instanceof java.net.Socket) ||
|
||||
(fdObj instanceof java.net.ServerSocket)) {
|
||||
cl = fdObj.getClass();
|
||||
f = cl.getDeclaredField("impl");
|
||||
f.setAccessible(true);
|
||||
val = f.get(fdObj);
|
||||
cl = f.getType();
|
||||
f = cl.getDeclaredField("fd");
|
||||
f.setAccessible(true);
|
||||
implVal = f.get(val);
|
||||
cl = f.getType();
|
||||
f = cl.getDeclaredField("fd");
|
||||
f.setAccessible(true);
|
||||
return ((Integer) f.get(implVal)).intValue();
|
||||
} else if ( fdObj instanceof java.io.FileDescriptor ) {
|
||||
cl = fdObj.getClass();
|
||||
f = cl.getDeclaredField("fd");
|
||||
f.setAccessible(true);
|
||||
return ((Integer) f.get(fdObj)).intValue();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Illegal Object type.");
|
||||
}
|
||||
}
|
||||
|
||||
// Actual NATIVE calls
|
||||
|
||||
private static native int nativeInit();
|
||||
private native int nativeCreatePoller(int maxFd) throws Exception;
|
||||
private native void nativeDestroyPoller(int handle) throws Exception;
|
||||
private native int nativeAddFd(int handle, int fd, short events)
|
||||
throws Exception;
|
||||
private native int nativeRemoveFd(int handle, int fd) throws Exception;
|
||||
private native int nativeRemoveIndex(int handle, int index)
|
||||
throws Exception;
|
||||
private native int nativeIsMember(int handle, int fd) throws Exception;
|
||||
private native int nativeWait(int handle, int maxRet, int[] fds,
|
||||
short[] events, long timeout)
|
||||
throws Exception;
|
||||
/**
|
||||
* Get number of active CPUs in this machine
|
||||
* to determine proper level of concurrency.
|
||||
*/
|
||||
public static native int getNumCPUs();
|
||||
|
||||
static {
|
||||
System.loadLibrary("poller");
|
||||
nativeInit();
|
||||
}
|
||||
}
|
@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.lang.Byte;
|
||||
|
||||
/**
|
||||
* Simple Java "server" using the Poller class
|
||||
* to multiplex on incoming connections. Note
|
||||
* that handoff of events, via linked Q is not
|
||||
* actually be a performance booster here, since
|
||||
* the processing of events is cheaper than
|
||||
* the overhead in scheduling/executing them.
|
||||
* Although this demo does allow for concurrency
|
||||
* in handling connections, it uses a rather
|
||||
* primitive "gang scheduling" policy to keep
|
||||
* the code simpler.
|
||||
*/
|
||||
|
||||
public class PollingServer
|
||||
{
|
||||
public final static int MAXCONN = 10000;
|
||||
public final static int PORTNUM = 4444;
|
||||
public final static int BYTESPEROP = 10;
|
||||
|
||||
/**
|
||||
* This synchronization object protects access to certain
|
||||
* data (bytesRead,eventsToProcess) by concurrent Consumer threads.
|
||||
*/
|
||||
private final static Object eventSync = new Object();
|
||||
|
||||
private static InputStream[] instr = new InputStream[MAXCONN];
|
||||
private static int[] mapping = new int[65535];
|
||||
private static LinkedQueue linkedQ = new LinkedQueue();
|
||||
private static int bytesRead = 0;
|
||||
private static int bytesToRead;
|
||||
private static int eventsToProcess=0;
|
||||
|
||||
public PollingServer(int concurrency) {
|
||||
Socket[] sockArr = new Socket[MAXCONN];
|
||||
long timestart, timestop;
|
||||
short[] revents = new short[MAXCONN];
|
||||
int[] fds = new int[MAXCONN];
|
||||
int bytes;
|
||||
Poller Mux;
|
||||
int serverFd;
|
||||
int totalConn=0;
|
||||
int connects=0;
|
||||
|
||||
System.out.println ("Serv: Initializing port " + PORTNUM);
|
||||
try {
|
||||
|
||||
ServerSocket skMain = new ServerSocket (PORTNUM);
|
||||
/*
|
||||
* Create the Poller object Mux, allow for up to MAXCONN
|
||||
* sockets/filedescriptors to be polled.
|
||||
*/
|
||||
Mux = new Poller(MAXCONN);
|
||||
serverFd = Mux.add(skMain, Poller.POLLIN);
|
||||
|
||||
Socket ctrlSock = skMain.accept();
|
||||
|
||||
BufferedReader ctrlReader =
|
||||
new BufferedReader(new InputStreamReader(ctrlSock.getInputStream()));
|
||||
String ctrlString = ctrlReader.readLine();
|
||||
bytesToRead = Integer.valueOf(ctrlString).intValue();
|
||||
ctrlString = ctrlReader.readLine();
|
||||
totalConn = Integer.valueOf(ctrlString).intValue();
|
||||
|
||||
System.out.println("Receiving " + bytesToRead + " bytes from " +
|
||||
totalConn + " client connections");
|
||||
|
||||
timestart = System.currentTimeMillis();
|
||||
|
||||
/*
|
||||
* Start the consumer threads to read data.
|
||||
*/
|
||||
for (int consumerThread = 0;
|
||||
consumerThread < concurrency; consumerThread++ ) {
|
||||
new Consumer(consumerThread).start();
|
||||
}
|
||||
|
||||
/*
|
||||
* Take connections, read Data
|
||||
*/
|
||||
int numEvents=0;
|
||||
|
||||
while ( bytesRead < bytesToRead ) {
|
||||
|
||||
int loopWaits=0;
|
||||
while (eventsToProcess > 0) {
|
||||
synchronized (eventSync) {
|
||||
loopWaits++;
|
||||
if (eventsToProcess <= 0) break;
|
||||
try { eventSync.wait(); } catch (Exception e) {e.printStackTrace();};
|
||||
}
|
||||
}
|
||||
if (loopWaits > 1)
|
||||
System.out.println("Done waiting...loops = " + loopWaits +
|
||||
" events " + numEvents +
|
||||
" bytes read : " + bytesRead );
|
||||
|
||||
if (bytesRead >= bytesToRead) break; // may be done!
|
||||
|
||||
/*
|
||||
* Wait for events
|
||||
*/
|
||||
numEvents = Mux.waitMultiple(100, fds, revents);
|
||||
synchronized (eventSync) {
|
||||
eventsToProcess = numEvents;
|
||||
}
|
||||
/*
|
||||
* Process all the events we got from Mux.waitMultiple
|
||||
*/
|
||||
int cnt = 0;
|
||||
while ( (cnt < numEvents) && (bytesRead < bytesToRead) ) {
|
||||
int fd = fds[cnt];
|
||||
|
||||
if (revents[cnt] == Poller.POLLIN) {
|
||||
if (fd == serverFd) {
|
||||
/*
|
||||
* New connection coming in on the ServerSocket
|
||||
* Add the socket to the Mux, keep track of mapping
|
||||
* the fdval returned by Mux.add to the connection.
|
||||
*/
|
||||
sockArr[connects] = skMain.accept();
|
||||
instr[connects] = sockArr[connects].getInputStream();
|
||||
int fdval = Mux.add(sockArr[connects], Poller.POLLIN);
|
||||
mapping[fdval] = connects;
|
||||
synchronized(eventSync) {
|
||||
eventsToProcess--; // just processed this one!
|
||||
}
|
||||
connects++;
|
||||
} else {
|
||||
/*
|
||||
* We've got data from this client connection.
|
||||
* Put it on the queue for the consumer threads to process.
|
||||
*/
|
||||
linkedQ.put(new Integer(fd));
|
||||
}
|
||||
} else {
|
||||
System.out.println("Got revents[" + cnt + "] == " + revents[cnt]);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
timestop = System.currentTimeMillis();
|
||||
System.out.println("Time for all reads (" + totalConn +
|
||||
" sockets) : " + (timestop-timestart));
|
||||
|
||||
// Tell the client it can now go away
|
||||
byte[] buff = new byte[BYTESPEROP];
|
||||
ctrlSock.getOutputStream().write(buff,0,BYTESPEROP);
|
||||
|
||||
// Tell the cunsumer threads they can exit.
|
||||
for (int cThread = 0; cThread < concurrency; cThread++ ) {
|
||||
linkedQ.put(new Integer(-1));
|
||||
}
|
||||
} catch (Exception exc) { exc.printStackTrace(); }
|
||||
}
|
||||
|
||||
/*
|
||||
* main ... just check if a concurrency was specified
|
||||
*/
|
||||
public static void main (String args[])
|
||||
{
|
||||
int concurrency;
|
||||
|
||||
if (args.length == 1)
|
||||
concurrency = java.lang.Integer.valueOf(args[0]).intValue();
|
||||
else
|
||||
concurrency = Poller.getNumCPUs() + 1;
|
||||
PollingServer server = new PollingServer(concurrency);
|
||||
}
|
||||
|
||||
/*
|
||||
* This class is for handling the Client data.
|
||||
* The PollingServer spawns off a number of these based upon
|
||||
* the number of CPUs (or concurrency argument).
|
||||
* Each just loops grabbing events off the queue and
|
||||
* processing them.
|
||||
*/
|
||||
class Consumer extends Thread {
|
||||
private int threadNumber;
|
||||
public Consumer(int i) { threadNumber = i; }
|
||||
|
||||
public void run() {
|
||||
byte[] buff = new byte[BYTESPEROP];
|
||||
int bytes = 0;
|
||||
|
||||
InputStream instream;
|
||||
while (bytesRead < bytesToRead) {
|
||||
try {
|
||||
Integer Fd = (Integer) linkedQ.take();
|
||||
int fd = Fd.intValue();
|
||||
if (fd == -1) break; /* got told we could exit */
|
||||
|
||||
/*
|
||||
* We have to map the fd value returned from waitMultiple
|
||||
* to the actual input stream associated with that fd.
|
||||
* Take a look at how the Mux.add() was done to see how
|
||||
* we stored that.
|
||||
*/
|
||||
int map = mapping[fd];
|
||||
instream = instr[map];
|
||||
bytes = instream.read(buff,0,BYTESPEROP);
|
||||
} catch (Exception e) { System.out.println(e.toString()); }
|
||||
|
||||
if (bytes > 0) {
|
||||
/*
|
||||
* Any real server would do some synchronized and some
|
||||
* unsynchronized work on behalf of the client, and
|
||||
* most likely send some data back...but this is a
|
||||
* gross oversimplification.
|
||||
*/
|
||||
synchronized(eventSync) {
|
||||
bytesRead += bytes;
|
||||
eventsToProcess--;
|
||||
if (eventsToProcess <= 0) {
|
||||
eventSync.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
README.txt
|
||||
|
||||
|
||||
This Poller class demonstrates access to poll(2) functionality in Java.
|
||||
|
||||
Requires Solaris production (native threads) JDK 1.2 or later, currently
|
||||
the C code compiles only on Solaris (SPARC and Intel).
|
||||
|
||||
Poller.java is the class, Poller.c is the supporting JNI code.
|
||||
|
||||
PollingServer.java is a sample application which uses the Poller class
|
||||
to multiplex sockets.
|
||||
|
||||
SimpleServer.java is the functional equivalent that does not multiplex
|
||||
but uses a single thread to handle each client connection.
|
||||
|
||||
Client.java is a sample application to drive against either server.
|
||||
|
||||
To build the Poller class and client/server demo :
|
||||
javac PollingServer.java Client.java
|
||||
javah Poller
|
||||
cc -G -o libpoller.so -I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/solaris\
|
||||
Poller.c
|
||||
|
||||
You will need to set the environment variable LD_LIBRARY_PATH to search
|
||||
the directory containing libpoller.so.
|
||||
|
||||
To use client/server, bump up your fd limit to handle the connections you
|
||||
want (need root access to go beyond 1024). For info on changing your file
|
||||
descriptor limit, type "man limit". If you are using Solaris 2.6
|
||||
or later, a regression in loopback read() performance may hit you at low
|
||||
numbers of connections, so run the client on another machine.
|
||||
|
||||
BASICs of Poller class usage :
|
||||
run "javadoc Poller" or see Poller.java for more details.
|
||||
|
||||
{
|
||||
Poller Mux = new Poller(65535); // allow it to contain 64K IO objects
|
||||
|
||||
int fd1 = Mux.add(socket1, Poller.POLLIN);
|
||||
...
|
||||
int fdN = Mux.add(socketN, Poller.POLLIN);
|
||||
|
||||
int[] fds = new int[100];
|
||||
short[] revents = new revents[100];
|
||||
|
||||
int numEvents = Mux.waitMultiple(100, fds, revents, timeout);
|
||||
|
||||
for (int i = 0; i < numEvents; i++) {
|
||||
/*
|
||||
* Probably need more sophisticated mapping scheme than this!
|
||||
*/
|
||||
if (fds[i] == fd1) {
|
||||
System.out.println("Got data on socket1");
|
||||
socket1.getInputStream().read(byteArray);
|
||||
// Do something based upon state of fd1 connection
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
Poller class implementation notes :
|
||||
|
||||
Currently all add(),remove(),isMember(), and waitMultiple() methods
|
||||
are synchronized for each Poller object. If one thread is blocked in
|
||||
pObj.waitMultiple(), another thread calling pObj.add(fd) will block
|
||||
until waitMultiple() returns. There is no provided mechanism to
|
||||
interrupt waitMultiple(), as one might expect a ServerSocket to be in
|
||||
the list waited on (see PollingServer.java).
|
||||
|
||||
One might also need to interrupt waitMultiple() to remove()
|
||||
fds/sockets, in which case one could create a Pipe or loopback localhost
|
||||
connection (at the level of PollingServer) and use a write() to that
|
||||
connection to interrupt. Or, better, one could queue up deletions
|
||||
until the next return of waitMultiple(). Or one could implement an
|
||||
interrupt mechanism in the JNI C code using a pipe(), and expose that
|
||||
at the Java level.
|
||||
|
||||
If frequent deletions/re-additions of socks/fds is to be done with
|
||||
very large sets of monitored fds, the Solaris 7 kernel cache will
|
||||
likely perform poorly without some tuning. One could differentiate
|
||||
between deleted (no longer cared for) fds/socks and those that are
|
||||
merely being disabled while data is processed on their behalf. In
|
||||
that case, re-enabling a disabled fd/sock could put it in it's
|
||||
original position in the poll array, thereby increasing the kernel
|
||||
cache performance. This would best be done in Poller.c. Of course
|
||||
this is not necessary for optimal /dev/poll performance.
|
||||
|
||||
Caution...the next paragraph gets a little technical for the
|
||||
benefit of those who already understand poll()ing fairly well. Others
|
||||
may choose to skip over it to read notes on the demo server.
|
||||
|
||||
An optimal solution for frequent enabling/disabling of socks/fds
|
||||
could involve a separately synchronized structure of "async"
|
||||
operations. Using a simple array (0..64k) containing the action
|
||||
(ADD,ENABLE,DISABLE, NONE), the events, and the index into the poll
|
||||
array, and having nativeWait() wake up in the poll() call periodically
|
||||
to process these async operations, I was able to speed up performance
|
||||
of the PollingServer by a factor of 2x at 8000 connections. Of course
|
||||
much of that gain was from the fact that I could (with the advent of
|
||||
an asyncAdd() method) move the accept() loop into a separate thread
|
||||
from the main poll() loop, and avoid the overhead of calling poll()
|
||||
with up to 7999 fds just for an accept. In implementing the async
|
||||
Disable/Enable, a further large optimization was to auto-disable fds
|
||||
with events available (before return from nativeWait()), so I could
|
||||
just call asyncEnable(fd) after processing (read()ing) the available
|
||||
data. This removed the need for inefficient gang-scheduling the
|
||||
attached PollingServer uses. In order to separately synchronize the
|
||||
async structure, yet still be able to operate on it from within
|
||||
nativeWait(), synchronization had to be done at the C level here. Due
|
||||
to the new complexities this introduced, as well as the fact that it
|
||||
was tuned specifically for Solaris 7 poll() improvements (not
|
||||
/dev/poll), this extra logic was left out of this demo.
|
||||
|
||||
|
||||
Client/Server Demo Notes :
|
||||
|
||||
Do not run the sample client/server with high numbers of connections
|
||||
unless you have a lot of free memory on your machine, as it can saturate
|
||||
CPU and lock you out of CDE just by its very resource intensive nature
|
||||
(much more so the SimpleServer than PollingServer).
|
||||
|
||||
Different OS versions will behave very differently as far as poll()
|
||||
performance (or /dev/poll existence) but, generally, real world applications
|
||||
"hit the wall" much earlier when a separate thread is used to handle
|
||||
each client connection. Issues of thread synchronization and locking
|
||||
granularity become performance killers. There is some overhead associated
|
||||
with multiplexing, such as keeping track of the state of each connection; as
|
||||
the number of connections gets very large, however, this overhead is more
|
||||
than made up for by the reduced synchronization overhead.
|
||||
|
||||
As an example, running the servers on a Solaris 7 PC (Pentium II-350 x
|
||||
2 CPUS) with 1 GB RAM, and the client on an Ultra-2, I got the following
|
||||
times (shorter is better) :
|
||||
|
||||
1000 connections :
|
||||
|
||||
PollingServer took 11 seconds
|
||||
SimpleServer took 12 seconds
|
||||
|
||||
4000 connections :
|
||||
|
||||
PollingServer took 20 seconds
|
||||
SimpleServer took 37 seconds
|
||||
|
||||
8000 connections :
|
||||
|
||||
PollingServer took 39 seconds
|
||||
SimpleServer took 1:48 seconds
|
||||
|
||||
This demo is not, however, meant to be considered some form of proof
|
||||
that multiplexing with the Poller class will gain you performance; this
|
||||
code is actually very heavily biased towards the non-polling server as
|
||||
very little synchronization is done, and most of the overhead is in the
|
||||
kernel IO for both servers. Use of multiplexing may be helpful in
|
||||
many, but certainly not all, circumstances.
|
||||
|
||||
Benchmarking a major Java server application which can run
|
||||
in a single-thread-per-client mode or using the new Poller class showed
|
||||
Poller provided a 253% improvement in throughput at a moderate load, as
|
||||
well as a 300% improvement in peak capacity. It also yielded a 21%
|
||||
smaller memory footprint at the lower load level.
|
||||
|
||||
Finally, there is code in Poller.c to take advantage of /dev/poll
|
||||
on OS versions that have that device; however, DEVPOLL must be defined
|
||||
in compiling Poller.c (and it must be compiled on a machine with
|
||||
/usr/include/sys/devpoll.h) to use it. Code compiled with DEVPOLL
|
||||
turned on will work on machines that don't have kernel support for
|
||||
the device, as it will fall back to using poll() in those cases.
|
||||
Currently /dev/poll does not correctly return an error if you attempt
|
||||
to remove() an object that was never added, but this should be fixed
|
||||
in an upcoming /dev/poll patch. The binary as shipped is not built with
|
||||
/dev/poll support as our build machine does not have devpoll.h.
|
||||
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.lang.Byte;
|
||||
|
||||
/**
|
||||
* Simple Java "server" using a single thread to handle each connection.
|
||||
*/
|
||||
|
||||
public class SimpleServer
|
||||
{
|
||||
private final static int BYTESPEROP= PollingServer.BYTESPEROP;
|
||||
private final static int PORTNUM = PollingServer.PORTNUM;
|
||||
private final static int MAXCONN = PollingServer.MAXCONN;
|
||||
|
||||
/*
|
||||
* This synchronization object protects access to certain
|
||||
* data (bytesRead,eventsToProcess) by concurrent Consumer threads.
|
||||
*/
|
||||
private final static Object eventSync = new Object();
|
||||
|
||||
private static InputStream[] instr = new InputStream[MAXCONN];
|
||||
private static int bytesRead;
|
||||
private static int bytesToRead;
|
||||
|
||||
public SimpleServer() {
|
||||
Socket[] sockArr = new Socket[MAXCONN];
|
||||
long timestart, timestop;
|
||||
int bytes;
|
||||
int totalConn=0;
|
||||
|
||||
|
||||
System.out.println ("Serv: Initializing port " + PORTNUM);
|
||||
try {
|
||||
|
||||
ServerSocket skMain = new ServerSocket (PORTNUM);
|
||||
|
||||
bytesRead = 0;
|
||||
Socket ctrlSock = skMain.accept();
|
||||
|
||||
BufferedReader ctrlReader =
|
||||
new BufferedReader(new InputStreamReader(ctrlSock.getInputStream()));
|
||||
String ctrlString = ctrlReader.readLine();
|
||||
bytesToRead = Integer.valueOf(ctrlString).intValue();
|
||||
ctrlString = ctrlReader.readLine();
|
||||
totalConn = Integer.valueOf(ctrlString).intValue();
|
||||
|
||||
System.out.println("Receiving " + bytesToRead + " bytes from " +
|
||||
totalConn + " client connections");
|
||||
|
||||
timestart = System.currentTimeMillis();
|
||||
|
||||
/*
|
||||
* Take connections, spawn off connection handling threads
|
||||
*/
|
||||
ConnHandler[] connHA = new ConnHandler[MAXCONN];
|
||||
int conn = 0;
|
||||
while ( conn < totalConn ) {
|
||||
Socket sock = skMain.accept();
|
||||
connHA[conn] = new ConnHandler(sock.getInputStream());
|
||||
connHA[conn].start();
|
||||
conn++;
|
||||
}
|
||||
|
||||
while ( bytesRead < bytesToRead ) {
|
||||
java.lang.Thread.sleep(500);
|
||||
}
|
||||
timestop = System.currentTimeMillis();
|
||||
System.out.println("Time for all reads (" + totalConn +
|
||||
" sockets) : " + (timestop-timestart));
|
||||
// Tell the client it can now go away
|
||||
byte[] buff = new byte[BYTESPEROP];
|
||||
ctrlSock.getOutputStream().write(buff,0,BYTESPEROP);
|
||||
} catch (Exception exc) { exc.printStackTrace(); }
|
||||
}
|
||||
|
||||
/*
|
||||
* main ... just create invoke the SimpleServer constructor.
|
||||
*/
|
||||
public static void main (String args[])
|
||||
{
|
||||
SimpleServer server = new SimpleServer();
|
||||
}
|
||||
|
||||
/*
|
||||
* Connection Handler inner class...one of these per client connection.
|
||||
*/
|
||||
class ConnHandler extends Thread {
|
||||
private InputStream instr;
|
||||
public ConnHandler(InputStream inputStr) { instr = inputStr; }
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
int bytes;
|
||||
byte[] buff = new byte[BYTESPEROP];
|
||||
|
||||
while ( bytesRead < bytesToRead ) {
|
||||
bytes = instr.read (buff, 0, BYTESPEROP);
|
||||
if (bytes > 0 ) {
|
||||
synchronized(eventSync) {
|
||||
bytesRead += bytes;
|
||||
}
|
||||
/*
|
||||
* Any real server would do some synchronized and some
|
||||
* unsynchronized work on behalf of the client, and
|
||||
* most likely send some data back...but this is a
|
||||
* gross oversimplification.
|
||||
*/
|
||||
}
|
||||
else {
|
||||
if (bytesRead < bytesToRead)
|
||||
System.out.println("instr.read returned : " + bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {e.printStackTrace();}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>OpenJDK 7 Command</string>
|
||||
<string>OpenJDK Command</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1797,12 +1797,19 @@ public class ObjectInputStream
|
||||
} catch (ClassNotFoundException ex) {
|
||||
resolveEx = ex;
|
||||
}
|
||||
|
||||
// Call filterCheck on the class before reading anything else
|
||||
filterCheck(cl, -1);
|
||||
|
||||
skipCustomData();
|
||||
|
||||
desc.initProxy(cl, resolveEx, readClassDesc(false));
|
||||
|
||||
// Call filterCheck on the definition
|
||||
filterCheck(desc.forClass(), -1);
|
||||
try {
|
||||
totalObjectRefs++;
|
||||
depth++;
|
||||
desc.initProxy(cl, resolveEx, readClassDesc(false));
|
||||
} finally {
|
||||
depth--;
|
||||
}
|
||||
|
||||
handles.finish(descHandle);
|
||||
passHandle = descHandle;
|
||||
@ -1847,12 +1854,19 @@ public class ObjectInputStream
|
||||
} catch (ClassNotFoundException ex) {
|
||||
resolveEx = ex;
|
||||
}
|
||||
|
||||
// Call filterCheck on the class before reading anything else
|
||||
filterCheck(cl, -1);
|
||||
|
||||
skipCustomData();
|
||||
|
||||
desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
|
||||
|
||||
// Call filterCheck on the definition
|
||||
filterCheck(desc.forClass(), -1);
|
||||
try {
|
||||
totalObjectRefs++;
|
||||
depth++;
|
||||
desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
|
||||
} finally {
|
||||
depth--;
|
||||
}
|
||||
|
||||
handles.finish(descHandle);
|
||||
passHandle = descHandle;
|
||||
|
@ -84,7 +84,7 @@ import java.util.*;
|
||||
* {(x, y) such that x.equals(y)}. </pre><p>
|
||||
*
|
||||
* This interface is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @param <T> the type of objects that this object may be compared to
|
||||
|
@ -29,7 +29,7 @@ package java.lang;
|
||||
* Thrown to indicate that the requested operation is not supported.<p>
|
||||
*
|
||||
* This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
|
@ -143,8 +143,10 @@ public abstract class Reference<T> {
|
||||
/*
|
||||
* system property to disable clearing before enqueuing.
|
||||
*/
|
||||
private static final boolean disableClearBeforeEnqueue
|
||||
= Boolean.getBoolean("jdk.lang.ref.disableClearBeforeEnqueue");
|
||||
private static final class ClearBeforeEnqueue {
|
||||
static final boolean DISABLE =
|
||||
Boolean.getBoolean("jdk.lang.ref.disableClearBeforeEnqueue");
|
||||
}
|
||||
|
||||
/*
|
||||
* Atomically get and clear (set to null) the VM's pending list.
|
||||
@ -297,7 +299,7 @@ public abstract class Reference<T> {
|
||||
* it was not registered with a queue when it was created
|
||||
*/
|
||||
public boolean enqueue() {
|
||||
if (!disableClearBeforeEnqueue)
|
||||
if (!ClearBeforeEnqueue.DISABLE)
|
||||
this.referent = null;
|
||||
return this.queue.enqueue(this);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -44,8 +44,8 @@ import java.util.StringJoiner;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
import sun.net.RegisteredDomain;
|
||||
import sun.net.PortConfig;
|
||||
import sun.security.util.RegisteredDomain;
|
||||
import sun.security.util.SecurityConstants;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
@ -678,13 +678,18 @@ public final class SocketPermission extends Permission
|
||||
String a = cname.toLowerCase();
|
||||
String b = hname.toLowerCase();
|
||||
if (a.startsWith(b) &&
|
||||
((a.length() == b.length()) || (a.charAt(b.length()) == '.')))
|
||||
((a.length() == b.length()) || (a.charAt(b.length()) == '.'))) {
|
||||
return true;
|
||||
}
|
||||
if (cdomain == null) {
|
||||
cdomain = RegisteredDomain.getRegisteredDomain(a);
|
||||
cdomain = RegisteredDomain.from(a)
|
||||
.map(RegisteredDomain::name)
|
||||
.orElse(a);
|
||||
}
|
||||
if (hdomain == null) {
|
||||
hdomain = RegisteredDomain.getRegisteredDomain(b);
|
||||
hdomain = RegisteredDomain.from(b)
|
||||
.map(RegisteredDomain::name)
|
||||
.orElse(b);
|
||||
}
|
||||
|
||||
return cdomain.length() != 0 && hdomain.length() != 0
|
||||
|
@ -49,7 +49,7 @@ package java.util;
|
||||
* the collection being implemented admits a more efficient implementation.<p>
|
||||
*
|
||||
* This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
|
@ -62,7 +62,7 @@ import java.util.function.Consumer;
|
||||
* collection being implemented admits a more efficient implementation.
|
||||
*
|
||||
* <p>This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
|
@ -52,7 +52,7 @@ import java.util.Map.Entry;
|
||||
* map being implemented admits a more efficient implementation.
|
||||
*
|
||||
* <p>This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @param <K> the type of keys maintained by this map
|
||||
|
@ -54,7 +54,7 @@ package java.util;
|
||||
* instead subclassing {@link AbstractCollection}.
|
||||
*
|
||||
* <p>This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @since 1.5
|
||||
|
@ -54,7 +54,7 @@ package java.util;
|
||||
* specification.<p>
|
||||
*
|
||||
* This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
|
@ -42,7 +42,7 @@ package java.util;
|
||||
* for {@code equals} and {@code hashCode}.<p>
|
||||
*
|
||||
* This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @param <E> the type of elements maintained by this set
|
||||
|
@ -79,7 +79,7 @@ import java.util.function.UnaryOperator;
|
||||
* Iterator} interfaces.
|
||||
*
|
||||
* <p>This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @author Josh Bloch and Doug Lea
|
||||
|
@ -91,7 +91,7 @@ import java.util.function.UnaryOperator;
|
||||
* should be used only to detect bugs.</i>
|
||||
*
|
||||
* <p>This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @param <E> the type of elements in this list
|
||||
|
@ -62,7 +62,7 @@ import java.util.stream.StreamSupport;
|
||||
* a MergeSort, but it does have to be <i>stable</i>.)
|
||||
*
|
||||
* <p>This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
@ -8899,4 +8899,4 @@ public class Arrays {
|
||||
|
||||
return aLength != bLength ? length : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user