OpenJDK / jdk / jdk12
changeset 28684:6a4680c5ed35
Merge
author | lana |
---|---|
date | Thu, 29 Jan 2015 15:35:29 -0800 |
parents | 6f1a91a49ba4 a36c179aa292 |
children | 6e8154707178 |
files | jdk/make/data/checkdeps/refs.allowed jdk/make/src/classes/build/tools/deps/CheckDeps.java jdk/src/java.base/aix/native/libnet/java/net/aix_close.c jdk/src/java.base/unix/classes/java/lang/UNIXProcess.java jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c jdk/src/java.base/unix/native/libjava/java_props_macosx.c jdk/src/java.base/unix/native/libjava/java_props_macosx.h jdk/src/java.base/unix/native/libnet/bsd_close.c jdk/src/java.base/unix/native/libnet/linux_close.c jdk/src/java.base/unix/native/libnet/solaris_close.c jdk/src/jdk.security.auth/unix/native/libjaas/Solaris.c jdk/test/java/lang/CharSequence/DefaultTest.java jdk/test/java/util/ResourceBundle/Bug6287579.java |
diffstat | 88 files changed, 7511 insertions(+), 4240 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/make/Tools.gmk Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/make/Tools.gmk Thu Jan 29 15:35:29 2015 -0800 @@ -34,28 +34,23 @@ include NativeCompilation.gmk include SetupJavaCompilers.gmk -# The exception handling of swing beaninfo which have the own tool directory -ifeq (, $(BUILD_TOOLS_JDK)) - $(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \ - SETUP := GENERATE_OLDBYTECODE, \ - ADD_JAVAC_FLAGS := "-Xbootclasspath/p:$(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes", \ - SRC := $(JDK_TOPDIR)/make/src/classes, \ - BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \ - COPY := boot.modules ext.modules)) -endif +################################################################################ -$(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources/%.template: \ - $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/%.template - $(call install-file) +$(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \ + SETUP := GENERATE_OLDBYTECODE, \ + ADD_JAVAC_FLAGS := "-Xbootclasspath/p:$(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes", \ + SRC := $(JDK_TOPDIR)/make/src/classes, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \ + COPY := boot.modules ext.modules)) -BUILD_TOOLS_JDK += $(foreach i, $(wildcard $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template), $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources/$(notdir $i)) +$(eval $(call SetupCopyFiles,COPY_NIMBUS_TEMPLATES, \ + SRC := $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus, \ + DEST := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources, \ + FILES := $(wildcard $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template))) -# Resource used by CheckDeps tool -$(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/deps/refs.allowed: \ - $(JDK_TOPDIR)/make/data/checkdeps/refs.allowed - $(call install-file) +BUILD_TOOLS_JDK += $(COPY_NIMBUS_TEMPLATES) -BUILD_TOOLS_JDK += $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/deps/refs.allowed +################################################################################ # Add a checksum ("jsum") to the end of a text file. Prevents trivial tampering with class lists. TOOL_ADDJSUM = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ @@ -130,10 +125,6 @@ TOOL_CLDRCONVERTER = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.cldrconverter.CLDRConverter -TOOL_CHECKDEPS = $(JAVA_SMALL) -Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR) \ - -cp "$(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes$(PATH_SEP)$(JDK_OUTPUTDIR)" \ - build.tools.deps.CheckDeps - TOOL_GENMODULESXML = $(JAVA_SMALL) -Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR) \ -cp "$(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes$(PATH_SEP)$(JDK_OUTPUTDIR)" \ build.tools.module.GenJdepsModulesXml @@ -161,25 +152,25 @@ # Tools needed on solaris because OBJCOPY is broken. ifeq ($(OPENJDK_TARGET_OS), solaris) -$(eval $(call SetupNativeCompilation,ADD_GNU_DEBUGLINK, \ - SRC := $(JDK_TOPDIR)/make/src/native/add_gnu_debuglink, \ - LANG := C, \ - CC := $(BUILD_CC), \ - LDEXE := $(BUILD_LD), \ - LDFLAGS := -lelf, \ - OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/add_gnu_debuglink, \ - OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \ - PROGRAM := add_gnu_debuglink)) + $(eval $(call SetupNativeCompilation,ADD_GNU_DEBUGLINK, \ + SRC := $(JDK_TOPDIR)/make/src/native/add_gnu_debuglink, \ + LANG := C, \ + CC := $(BUILD_CC), \ + LDEXE := $(BUILD_LD), \ + LDFLAGS := -lelf, \ + OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/add_gnu_debuglink, \ + OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \ + PROGRAM := add_gnu_debuglink)) -$(eval $(call SetupNativeCompilation,FIX_EMPTY_SEC_HDR_FLAGS, \ - SRC := $(JDK_TOPDIR)/make/src/native/fix_empty_sec_hdr_flags, \ - LANG := C, \ - CC := $(BUILD_CC), \ - LDEXE := $(BUILD_LD), \ - LDFLAGS := -lelf, \ - OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/fix_empty_sec_hdr_flags, \ - OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \ - PROGRAM := fix_empty_sec_hdr_flags)) + $(eval $(call SetupNativeCompilation,FIX_EMPTY_SEC_HDR_FLAGS, \ + SRC := $(JDK_TOPDIR)/make/src/native/fix_empty_sec_hdr_flags, \ + LANG := C, \ + CC := $(BUILD_CC), \ + LDEXE := $(BUILD_LD), \ + LDFLAGS := -lelf, \ + OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/fix_empty_sec_hdr_flags, \ + OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \ + PROGRAM := fix_empty_sec_hdr_flags)) endif $(BUILD_TOOLS_JDK): $(BUILD_INTERIM_JIMAGE)
--- a/jdk/make/data/checkdeps/refs.allowed Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -# -# This properties-formatted file contains the names of the non-existent types -# that are allowed to be referenced from classes in a profiles image. -# -# The property key is a type that does not exist. The property value is one or -# more types that reference the missing type. The property value also encodes -# the names of the profiles where this reference is allowed. - -# jsse.jar is not subsetted by the profiles build. For compact1 and compact2 -# then this means that there are references to Kerberos types that do not -# exist. These references are harmless. -# -javax.security.auth.kerberos.KerberosKey=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2 -javax.security.auth.kerberos.KerberosPrincipal=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2 -javax.security.auth.kerberos.KerberosTicket=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -javax.security.auth.kerberos.KeyTab=sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2 -javax.security.auth.kerberos.ServicePermission=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2 -sun.security.jgss.GSSCaller=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2 -sun.security.jgss.krb5.Krb5Util=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2 -sun.security.jgss.krb5.ServiceCreds=sun.security.ssl.krb5.Krb5ProxyImpl,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -sun.security.krb5.EncryptedData= sun.security.ssl.krb5.KerberosPreMasterSecret,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -sun.security.krb5.EncryptionKey=sun.security.ssl.krb5.KerberosPreMasterSecret,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -sun.security.krb5.internal.crypto.KeyUsage=sun.security.ssl.krb5.KerberosPreMasterSecret,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -sun.security.krb5.internal.EncTicketPart=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -sun.security.krb5.internal.Krb5=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -sun.security.krb5.internal.Ticket=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -sun.security.krb5.KrbException=sun.security.ssl.krb5.KerberosPreMasterSecret,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -sun.security.krb5.PrincipalName=sun.security.ssl.krb5.Krb5ProxyImpl,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 -sun.security.krb5.Realm=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2 - -# Residual references to java.beans. -# The RemoveMethods tool does not yet purge the constant pool. -# -java.beans.PropertyChangeListener=java.util.logging.LogManager,compact1,compact2,compact3
--- a/jdk/make/gensrc/GensrcMisc.gmk Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/make/gensrc/GensrcMisc.gmk Thu Jan 29 15:35:29 2015 -0800 @@ -28,6 +28,13 @@ # string and the runtime name into the Version.java file. # To be printed by java -version +# These dependencies should ideally be added to prerequesites for Version.java +# but skip for now until we have better incremental build for java. +# $(call DependOnVariable, LAUNCHER_NAME) \ +# $(call DependOnVariable, RELEASE) \ +# $(call DependOnVariable, FULL_VERSION) \ +# $(call DependOnVariable, RUNTIME_VERSION) + $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/misc/Version.java: \ $(JDK_TOPDIR)/src/java.base/share/classes/sun/misc/Version.java.template $(MKDIR) -p $(@D)
--- a/jdk/make/lib/CoreLibraries.gmk Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/make/lib/CoreLibraries.gmk Thu Jan 29 15:35:29 2015 -0800 @@ -74,8 +74,6 @@ ########################################################################################## -BUILD_LIBVERIFY_SRC := check_code.c check_format.c - ifeq ($(OPENJDK_TARGET_OS), solaris) ifneq ($(OPENJDK_TARGET_CPU), x86_64) BUILD_LIBVERIFY_REORDER := $(JDK_TOPDIR)/make/mapfiles/libverify/reorder-$(OPENJDK_TARGET_CPU) @@ -116,10 +114,6 @@ LIBJAVA_SRC_DIRS := $(call FindSrcDirsForLib, java.base, java) -ifeq ($(OPENJDK_TARGET_OS), macosx) - LIBJAVA_EXCLUDE_FILES += $(JDK_TOPDIR)/src/java.base/unix/native/libjava/HostLocaleProviderAdapter_md.c -endif - LIBJAVA_CFLAGS := $(addprefix -I, $(LIBJAVA_SRC_DIRS)) \ -I$(JDK_TOPDIR)/src/java.base/share/native/libfdlibm \ -I$(SUPPORT_OUTPUTDIR)/headers/java.base \ @@ -134,9 +128,7 @@ LIBJAVA_CFLAGS += -DJDK_UPDATE_VERSION='"$(JDK_UPDATE_VERSION)"' endif -ifneq ($(OPENJDK_TARGET_OS), macosx) - LIBJAVA_EXCLUDE_FILES += java_props_macosx.c -else +ifeq ($(OPENJDK_TARGET_OS), macosx) BUILD_LIBJAVA_java_props_md.c_CFLAGS := -x objective-c BUILD_LIBJAVA_java_props_macosx.c_CFLAGS := -x objective-c endif @@ -151,8 +143,6 @@ LIBRARY := java, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJAVA_SRC_DIRS), \ - EXCLUDES := fdlibm/src zip prefs, \ - EXCLUDE_FILES := $(LIBJAVA_EXCLUDE_FILES), \ LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(CFLAGS_JDKLIB) \ @@ -247,19 +237,10 @@ ########################################################################################## -BUILD_LIBJLI_SRC_DIRS := $(JDK_TOPDIR)/src/java.base/share/native/libjli \ - $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli +LIBJLI_SRC_DIRS := $(call FindSrcDirsForLib, java.base, jli) LIBJLI_CFLAGS := $(CFLAGS_JDKLIB) -BUILD_LIBJLI_FILES := \ - java.c \ - splashscreen_stubs.c \ - parse_manifest.c \ - version_comp.c \ - wildcard.c \ - jli_util.c - ifeq ($(JVM_VARIANT_ZERO), true) ERGO_FAMILY := zero else @@ -269,68 +250,55 @@ ERGO_FAMILY := $(OPENJDK_TARGET_CPU_ARCH) endif endif +LIBJLI_ALL_ERGO := $(wildcard $(addsuffix /ergo_*.c, $(LIBJLI_SRC_DIRS))) +LIBJLI_EXCLUDE_ERGO := $(filter-out %/ergo_$(ERGO_FAMILY).c, $(LIBJLI_ALL_ERGO)) +# If all specialized ergo files are excluded, use generic ergo +ifeq ($(LIBJLI_ALL_ERGO), $(LIBJLI_EXCLUDE_ERGO)) + LIBJLI_CFLAGS += -DUSE_GENERIC_ERGO +endif +LIBJLI_EXCLUDE_FILES += $(notdir $(LIBJLI_EXCLUDE_ERGO)) ifeq ($(OPENJDK_TARGET_OS), macosx) - BUILD_LIBJLI_SRC_DIRS += $(JDK_TOPDIR)/src/java.base/macosx/native/libjli - BUILD_LIBJLI_FILES += java_md_common.c java_md_macosx.c + LIBJLI_EXCLUDE_FILES += java_md_solinux.c ergo.c BUILD_LIBJLI_java_md_macosx.c_CFLAGS := -x objective-c BUILD_LIBJLI_STATIC_java_md_macosx.c_CFLAGS := -x objective-c + + LIBJLI_CFLAGS += -DPACKAGE_PATH=\"$(PACKAGE_PATH)\" endif ifeq ($(OPENJDK_TARGET_OS), windows) - BUILD_LIBJLI_FILES += java_md.c \ - cmdtoargs.c # Staticically link with c runtime on windows. LIBJLI_CFLAGS := $(filter-out -MD, $(LIBJLI_CFLAGS)) -else ifneq ($(OPENJDK_TARGET_OS), macosx) - - BUILD_LIBJLI_FILES += java_md_common.c - BUILD_LIBJLI_FILES += java_md_solinux.c ergo.c - - ERGO_ARCH_FILE = ergo_$(ERGO_FAMILY).c - - # if the architecture specific ergo file exists then - # use it, else use the generic definitions from ergo.c - ifneq ($(wildcard $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli/$(ERGO_ARCH_FILE)), ) - BUILD_LIBJLI_FILES += $(ERGO_ARCH_FILE) - else # !ERGO_ARCH_FILE - LIBJLI_CFLAGS += -DUSE_GENERIC_ERGO - endif # ERGO_ARCH_FILE -endif #WINDOWS - -LIBJLI_CFLAGS += $(foreach dir, $(BUILD_LIBJLI_SRC_DIRS), -I$(dir)) - -# Append defines depending on target platform -LIBJLI_CFLAGS += $(OPENJDK_TARGET_CPU_JLI_CFLAGS) - -ifeq ($(OPENJDK_TARGET_OS), macosx) - LIBJLI_CFLAGS += -DPACKAGE_PATH=\"$(PACKAGE_PATH)\" -endif - -ifneq ($(USE_EXTERNAL_LIBZ), true) - BUILD_LIBJLI_SRC_DIRS += $(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8 - LIBJLI_CFLAGS += $(ZLIB_CPPFLAGS) - BUILD_LIBJLI_FILES += \ - inflate.c \ - inftrees.c \ - inffast.c \ - zadler32.c \ - zcrc32.c \ - zutil.c -endif - -ifeq ($(OPENJDK_TARGET_OS), windows) LIBJLI_OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE) else LIBJLI_OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE)/jli endif +LIBJLI_CFLAGS += $(addprefix -I, $(LIBJLI_SRC_DIRS)) + +# Append defines depending on target platform +LIBJLI_CFLAGS += $(OPENJDK_TARGET_CPU_JLI_CFLAGS) + +ifneq ($(USE_EXTERNAL_LIBZ), true) + LIBJLI_CFLAGS += $(ZLIB_CPPFLAGS) + LIBJLI_EXTRA_FILES += \ + $(addprefix $(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8/, \ + inflate.c \ + inftrees.c \ + inffast.c \ + zadler32.c \ + zcrc32.c \ + zutil.c \ + ) +endif + $(eval $(call SetupNativeCompilation,BUILD_LIBJLI, \ LIBRARY := jli, \ OUTPUT_DIR := $(LIBJLI_OUTPUT_DIR), \ - SRC := $(BUILD_LIBJLI_SRC_DIRS), \ - INCLUDE_FILES := $(BUILD_LIBJLI_FILES), \ + SRC := $(LIBJLI_SRC_DIRS), \ + EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \ + EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \ LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(LIBJLI_CFLAGS), \ @@ -376,8 +344,9 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJLI_STATIC, \ STATIC_LIBRARY := jli_static, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE), \ - SRC := $(BUILD_LIBJLI_SRC_DIRS), \ - INCLUDE_FILES := $(BUILD_LIBJLI_FILES), \ + SRC := $(LIBJLI_SRC_DIRS), \ + EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \ + EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \ LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS), \ @@ -395,8 +364,9 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJLI_STATIC, \ LIBRARY := jli_static, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE), \ - SRC := $(BUILD_LIBJLI_SRC_DIRS), \ - INCLUDE_FILES := $(BUILD_LIBJLI_FILES), \ + SRC := $(LIBJLI_SRC_DIRS), \ + EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \ + EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \ LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBJLI_CFLAGS), \ @@ -411,16 +381,17 @@ else ifeq ($(OPENJDK_TARGET_OS), aix) # AIX also requires a static libjli because the compiler doesn't support '-rpath' - $(eval $(call SetupNativeCompilation,BUILD_LIBJLI_STATIC,\ - STATIC_LIBRARY:=jli_static,\ - OUTPUT_DIR:=$(SUPPORT_OUTPUTDIR)/native/$(MODULE),\ - SRC:=$(BUILD_LIBJLI_SRC_DIRS),\ - INCLUDE_FILES:=$(BUILD_LIBJLI_FILES),\ - LANG:=C,\ - OPTIMIZATION:=HIGH, \ - CFLAGS:=$(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS),\ - ARFLAGS:=$(ARFLAGS),\ - OBJECT_DIR:=$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static)) + $(eval $(call SetupNativeCompilation,BUILD_LIBJLI_STATIC, \ + STATIC_LIBRARY := jli_static, \ + OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE), \ + SRC := $(LIBJLI_SRC_DIRS), \ + EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \ + EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \ + LANG := C, \ + OPTIMIZATION := HIGH, \ + CFLAGS := $(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS), \ + ARFLAGS := $(ARFLAGS), \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static)) TARGETS += $(BUILD_LIBJLI_STATIC)
--- a/jdk/make/lib/Lib-jdk.attach.gmk Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/make/lib/Lib-jdk.attach.gmk Thu Jan 29 15:35:29 2015 -0800 @@ -31,7 +31,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBATTACH, \ LIBRARY := attach, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ - SRC := $(JDK_TOPDIR)/src/jdk.attach/$(OPENJDK_TARGET_OS)/native/libattach, \ + SRC := $(call FindSrcDirsForLib, jdk.attach, attach), \ LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) \
--- a/jdk/make/lib/Lib-jdk.security.auth.gmk Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/make/lib/Lib-jdk.security.auth.gmk Thu Jan 29 15:35:29 2015 -0800 @@ -28,9 +28,7 @@ ################################################################################ LIBJAAS_MAPFILE := -ifneq ($(OPENJDK_TARGET_OS), solaris) - LIBJAAS_EXCLUDE_FILES := Solaris.c -else +ifeq ($(OPENJDK_TARGET_OS), solaris) # only on solaris...wonder why LIBJAAS_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjaas/mapfile-vers endif @@ -43,7 +41,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJAAS, \ LIBRARY := $(LIBJAAS_NAME), \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ - SRC := $(JDK_TOPDIR)/src/jdk.security.auth/$(OPENJDK_TARGET_OS_TYPE)/native/libjaas, \ + SRC := $(call FindSrcDirsForLib, jdk.security.auth, jaas), \ LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/jdk.security.auth, \ @@ -53,7 +51,6 @@ LDFLAGS_windows := netapi32.lib user32.lib mpr.lib advapi32.lib, \ LDFLAGS_SUFFIX_windows := $(LDFLAGS_JDKLIB_SUFFIX), \ LDFLAGS_SUFFIX_solaris := -lc, \ - EXCLUDE_FILES := $(LIBJAAS_EXCLUDE_FILES), \ VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \ RC_FLAGS := $(RC_FLAGS) \ -D "JDK_FNAME=$(LIBJAAS_NAME).dll" \
--- a/jdk/make/lib/NetworkingLibraries.gmk Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/make/lib/NetworkingLibraries.gmk Thu Jan 29 15:35:29 2015 -0800 @@ -23,39 +23,16 @@ # questions. # -LIBNET_SRC_DIRS := $(JDK_TOPDIR)/src/java.base/share/native/libnet \ - $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libnet -LIBNET_CFLAGS += -I$(SUPPORT_OUTPUTDIR)/headers/java.base \ - $(LIBJAVA_HEADER_FLAGS) - -LIBNET_CFLAGS += $(foreach dir, $(LIBNET_SRC_DIRS), -I$(dir)) - -LIBNET_EXCLUDE_FILES := -ifneq ($(OPENJDK_TARGET_OS), solaris) - LIBNET_EXCLUDE_FILES += solaris_close.c -endif - -ifneq ($(OPENJDK_TARGET_OS), linux) - LIBNET_EXCLUDE_FILES += linux_close.c -endif - -ifneq ($(OPENJDK_TARGET_OS), macosx) - LIBNET_EXCLUDE_FILES += bsd_close.c -endif - -ifeq ($(OPENJDK_TARGET_OS), aix) - LIBNET_SRC_DIRS += $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libnet/java/net/ -endif +LIBNET_SRC_DIRS := $(call FindSrcDirsForLib, java.base, net) $(eval $(call SetupNativeCompilation,BUILD_LIBNET, \ LIBRARY := net, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBNET_SRC_DIRS), \ - EXCLUDE_FILES := $(LIBNET_EXCLUDE_FILES), \ LANG := C, \ OPTIMIZATION := LOW, \ - CFLAGS := $(CFLAGS_JDKLIB) \ - $(LIBNET_CFLAGS), \ + CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/java.base \ + $(LIBJAVA_HEADER_FLAGS) $(addprefix -I, $(LIBNET_SRC_DIRS)), \ MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libnet/mapfile-vers, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \
--- a/jdk/make/lib/NioLibraries.gmk Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/make/lib/NioLibraries.gmk Thu Jan 29 15:35:29 2015 -0800 @@ -65,7 +65,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(BUILD_LIBNIO_SRC), \ EXCLUDE_FILES := $(BUILD_LIBNIO_EXFILES), \ - EXCLUDES := sctp, \ LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(CFLAGS_JDKLIB) \
--- a/jdk/make/mapfiles/libjava/mapfile-vers Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/make/mapfiles/libjava/mapfile-vers Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2015, 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 @@ -214,10 +214,10 @@ Java_java_lang_Throwable_fillInStackTrace; Java_java_lang_Throwable_getStackTraceDepth; Java_java_lang_Throwable_getStackTraceElement; - Java_java_lang_UNIXProcess_init; - Java_java_lang_UNIXProcess_waitForProcessExit; - Java_java_lang_UNIXProcess_forkAndExec; - Java_java_lang_UNIXProcess_destroyProcess; + Java_java_lang_ProcessImpl_init; + Java_java_lang_ProcessImpl_waitForProcessExit; + Java_java_lang_ProcessImpl_forkAndExec; + Java_java_lang_ProcessImpl_destroyProcess; Java_java_nio_Bits_copyFromShortArray; Java_java_nio_Bits_copyToShortArray; Java_java_nio_Bits_copyFromIntArray;
--- a/jdk/make/src/classes/build/tools/deps/CheckDeps.java Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2013, 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. - */ - -package build.tools.deps; - -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.charset.StandardCharsets; -import java.util.Set; -import java.util.HashSet; -import java.util.Map; -import java.util.HashMap; -import java.util.Enumeration; -import java.util.Properties; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; - -import com.sun.tools.classfile.ClassFile; -import com.sun.tools.classfile.Dependencies; -import com.sun.tools.classfile.Dependency; - -/** - * A simple tool to check the JAR files in a JRE image to ensure that there - * aren't any references to types that do not exist. The tool is intended to - * be used in the JDK "profiles" build to help ensure that the profile - * definitions are kept up to date. - */ - -public class CheckDeps { - - // classfile API for finding dependencies - static final Dependency.Finder finder = Dependencies.getClassDependencyFinder(); - - // "known types", found in rt.jar or other JAR files - static final Set<String> knownTypes = new HashSet<>(); - - // References to unknown types. The map key is the unknown type, the - // map value is the set of classes that reference it. - static final Map<String,Set<String>> unknownRefs = new HashMap<>(); - - // The property name is the name of an unknown type that is allowed to be - // references. The property value is a comma separated list of the types - // that are allowed to reference it. The list also includes the names of - // the profiles that the reference is allowed. - static final Properties allowedBadRefs = new Properties(); - - /** - * Returns the class name for the given class file. In the case of inner - * classes then the enclosing class is returned in order to keep the - * rules simple. - */ - static String toClassName(String s) { - int i = s.indexOf('$'); - if (i > 0) - s = s.substring(0, i); - return s.replace("/", "."); - } - - /** - * Analyze the dependencies of all classes in the given JAR file. The - * method updates knownTypes and unknownRefs as part of the analysis. - */ - static void analyzeDependencies(Path jarpath) throws Exception { - System.out.format("Analyzing %s%n", jarpath); - try (JarFile jf = new JarFile(jarpath.toFile())) { - Enumeration<JarEntry> entries = jf.entries(); - while (entries.hasMoreElements()) { - JarEntry e = entries.nextElement(); - String name = e.getName(); - if (name.endsWith(".class")) { - ClassFile cf = ClassFile.read(jf.getInputStream(e)); - for (Dependency d : finder.findDependencies(cf)) { - String origin = toClassName(d.getOrigin().getName()); - String target = toClassName(d.getTarget().getName()); - - // origin is now known - unknownRefs.remove(origin); - knownTypes.add(origin); - - // if the target is not known then record the reference - if (!knownTypes.contains(target)) { - Set<String> refs = unknownRefs.get(target); - if (refs == null) { - // first time seeing this unknown type - refs = new HashSet<>(); - unknownRefs.put(target, refs); - } - refs.add(origin); - } - } - } - } - } - } - - /** - * We have closure (no references to types that do not exist) if - * unknownRefs is empty. When unknownRefs is not empty then it should - * only contain references that are allowed to be present (these are - * loaded from the refs.allowed properties file). - * - * @param the profile that is being tested, this determines the exceptions - * in {@code allowedBadRefs} that apply. - * - * @return {@code true} if there are no missing types or the only references - * to missing types are described by {@code allowedBadRefs}. - */ - static boolean checkClosure(String profile) { - // process the references to types that do not exist. - boolean fail = false; - for (Map.Entry<String,Set<String>> entry: unknownRefs.entrySet()) { - String target = entry.getKey(); - for (String origin: entry.getValue()) { - // check if origin -> target allowed - String value = allowedBadRefs.getProperty(target); - if (value == null) { - System.err.format("%s -> %s (unknown type)%n", origin, target); - fail = true; - } else { - // target is known, check if the origin is one that we - // expect and that the exception applies to the profile. - boolean found = false; - boolean applicable = false; - for (String s: value.split(",")) { - s = s.trim(); - if (s.equals(origin)) - found = true; - if (s.equals(profile)) - applicable = true; - } - if (!found || !applicable) { - if (!found) { - System.err.format("%s -> %s (not allowed)%n", origin, target); - } else { - System.err.format("%s -> %s (reference not applicable to %s)%n", - origin, target, profile); - } - fail = true; - } - } - - } - } - - return !fail; - } - - static void fail(URL url) throws Exception { - System.err.println("One or more unexpected references encountered"); - if (url != null) - System.err.format("Check %s is up to date%n", Paths.get(url.toURI())); - System.exit(-1); - } - - public static void main(String[] args) throws Exception { - // load properties file so that we know what missing types that are - // allowed to be referenced. - URL url = CheckDeps.class.getResource("refs.allowed"); - if (url != null) { - try (InputStream in = url.openStream()) { - allowedBadRefs.load(new InputStreamReader(in, StandardCharsets.UTF_8)); - } - } - - if (args.length != 2) { - System.err.println("Usage: java CheckDeps <image> <profile>"); - System.exit(-1); - } - - String image = args[0]; - String profile = args[1]; - - // process JAR files on boot class path - Path lib = Paths.get(image, "lib"); - try (DirectoryStream<Path> stream = Files.newDirectoryStream(lib, "*.jar")) { - for (Path jarpath: stream) { - analyzeDependencies(jarpath); - } - } - - // classes on boot class path should not reference other types - boolean okay = checkClosure(profile); - if (!okay) - fail(url); - - // process JAR files in the extensions directory - try (DirectoryStream<Path> stream = Files.newDirectoryStream(lib.resolve("ext"), "*.jar")) { - for (Path jarpath: stream) { - analyzeDependencies(jarpath); - } - } - - // re-check to ensure that the extensions doesn't reference types that - // do not exist. - okay = checkClosure(profile); - if (!okay) - fail(url); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/aix/native/libnet/aix_close.c Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2001, 2013, 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. + */ + +/* + * This file contains implementations of NET_... functions. The NET_.. functions are + * wrappers for common file- and socket functions plus provisions for non-blocking IO. + * + * (basically, the layers remember all file descriptors waiting for a particular fd; + * all threads waiting on a certain fd can be woken up by sending them a signal; this + * is done e.g. when the fd is closed.) + * + * This was originally copied from the linux_close.c implementation. + * + * Side Note: This coding needs initialization. Under Linux this is done + * automatically via __attribute((constructor)), on AIX this is done manually + * (see aix_close_init). + * + */ + +/* + AIX needs a workaround for I/O cancellation, see: + http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm + ... + The close subroutine is blocked until all subroutines which use the file + descriptor return to usr space. For example, when a thread is calling close + and another thread is calling select with the same file descriptor, the + close subroutine does not return until the select call returns. + ... +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/uio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/poll.h> + +/* + * Stack allocated by thread when doing blocking operation + */ +typedef struct threadEntry { + pthread_t thr; /* this thread */ + struct threadEntry *next; /* next thread */ + int intr; /* interrupted */ +} threadEntry_t; + +/* + * Heap allocated during initialized - one entry per fd + */ +typedef struct { + pthread_mutex_t lock; /* fd lock */ + threadEntry_t *threads; /* threads blocked on fd */ +} fdEntry_t; + +/* + * Signal to unblock thread + */ +static int sigWakeup = (SIGRTMAX - 1); + +/* + * The fd table and the number of file descriptors + */ +static fdEntry_t *fdTable = NULL; +static int fdCount = 0; + +/* + * Null signal handler + */ +static void sig_wakeup(int sig) { +} + +/* + * Initialization routine (executed when library is loaded) + * Allocate fd tables and sets up signal handler. + * + * On AIX we don't have __attribute((constructor)) so we need to initialize + * manually (from JNI_OnLoad() in 'src/share/native/java/net/net_util.c') + */ +void aix_close_init() { + struct rlimit nbr_files; + sigset_t sigset; + struct sigaction sa; + + /* Check already initialized */ + if (fdCount > 0 && fdTable != NULL) { + return; + } + + /* + * Allocate table based on the maximum number of + * file descriptors. + */ + if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { + fprintf(stderr, "library initialization failed - " + "unable to get max # of allocated fds\n"); + abort(); + } + fdCount = nbr_files.rlim_max; + /* + * We have a conceptual problem here, when the number of files is + * unlimited. As a kind of workaround, we ensure the table is big + * enough for handle even a large number of files. Since SAP itself + * recommends a limit of 32000 files, we just use 64000 as 'infinity'. + */ + if (nbr_files.rlim_max == RLIM_INFINITY) { + fdCount = 64000; + } + fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + if (fdTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor table - out of memory"); + abort(); + } + + { + int i; + for (i=0; i < fdCount; i++) { + pthread_mutex_init(&fdTable[i].lock, NULL); + } + } + + /* + * Setup the signal handler + */ + sa.sa_handler = sig_wakeup; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sigWakeup, &sa, NULL); + + sigemptyset(&sigset); + sigaddset(&sigset, sigWakeup); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); +} + +/* + * Return the fd table for this fd or NULL is fd out + * of range. + */ +static inline fdEntry_t *getFdEntry(int fd) +{ + if (fd < 0 || fd >= fdCount) { + return NULL; + } + return &fdTable[fd]; +} + +/* + * Start a blocking operation :- + * Insert thread onto thread list for the fd. + */ +static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) +{ + self->thr = pthread_self(); + self->intr = 0; + + pthread_mutex_lock(&(fdEntry->lock)); + { + self->next = fdEntry->threads; + fdEntry->threads = self; + } + pthread_mutex_unlock(&(fdEntry->lock)); +} + +/* + * End a blocking operation :- + * Remove thread from thread list for the fd + * If fd has been interrupted then set errno to EBADF + */ +static inline void endOp + (fdEntry_t *fdEntry, threadEntry_t *self) +{ + int orig_errno = errno; + pthread_mutex_lock(&(fdEntry->lock)); + { + threadEntry_t *curr, *prev=NULL; + curr = fdEntry->threads; + while (curr != NULL) { + if (curr == self) { + if (curr->intr) { + orig_errno = EBADF; + } + if (prev == NULL) { + fdEntry->threads = curr->next; + } else { + prev->next = curr->next; + } + break; + } + prev = curr; + curr = curr->next; + } + } + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; +} + +/* + * Close or dup2 a file descriptor ensuring that all threads blocked on + * the file descriptor are notified via a wakeup signal. + * + * fd1 < 0 => close(fd2) + * fd1 >= 0 => dup2(fd1, fd2) + * + * Returns -1 with errno set if operation fails. + */ +static int closefd(int fd1, int fd2) { + int rv, orig_errno; + fdEntry_t *fdEntry = getFdEntry(fd2); + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Lock the fd to hold-off additional I/O on this fd. + */ + pthread_mutex_lock(&(fdEntry->lock)); + + { + /* On fast machines we see that we enter dup2 before the + * accepting thread had a chance to get and process the signal. + * So in case we woke a thread up, give it some time to cope. + * Also see https://bugs.openjdk.java.net/browse/JDK-8006395 */ + int num_woken = 0; + + /* + * Send a wakeup signal to all threads blocked on this + * file descriptor. + */ + threadEntry_t *curr = fdEntry->threads; + while (curr != NULL) { + curr->intr = 1; + pthread_kill( curr->thr, sigWakeup ); + num_woken ++; + curr = curr->next; + } + + if (num_woken > 0) { + usleep(num_woken * 50); + } + + /* + * And close/dup the file descriptor + * (restart if interrupted by signal) + */ + do { + if (fd1 < 0) { + rv = close(fd2); + } else { + rv = dup2(fd1, fd2); + } + } while (rv == -1 && errno == EINTR); + } + + /* + * Unlock without destroying errno + */ + orig_errno = errno; + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; + + return rv; +} + +/* + * Wrapper for dup2 - same semantics as dup2 system call except + * that any threads blocked in an I/O system call on fd2 will be + * preempted and return -1/EBADF; + */ +int NET_Dup2(int fd, int fd2) { + if (fd < 0) { + errno = EBADF; + return -1; + } + return closefd(fd, fd2); +} + +/* + * Wrapper for close - same semantics as close system call + * except that any threads blocked in an I/O on fd will be + * preempted and the I/O system call will return -1/EBADF. + */ +int NET_SocketClose(int fd) { + return closefd(-1, fd); +} + +/************** Basic I/O operations here ***************/ + +/* + * Macro to perform a blocking IO operation. Restarts + * automatically if interrupted by signal (other than + * our wakeup signal) + */ +#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ + int ret; \ + threadEntry_t self; \ + fdEntry_t *fdEntry = getFdEntry(FD); \ + if (fdEntry == NULL) { \ + errno = EBADF; \ + return -1; \ + } \ + do { \ + startOp(fdEntry, &self); \ + ret = FUNC; \ + endOp(fdEntry, &self); \ + } while (ret == -1 && errno == EINTR); \ + return ret; \ +} + +int NET_Read(int s, void* buf, size_t len) { + BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); +} + +int NET_ReadV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, int *fromlen) { + socklen_t socklen = *fromlen; + BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, &socklen) ); + *fromlen = socklen; +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); +} + +int NET_WriteV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int + flags, const struct sockaddr *to, int tolen) { + BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); +} + +int NET_Accept(int s, struct sockaddr *addr, int *addrlen) { + socklen_t socklen = *addrlen; + BLOCKING_IO_RETURN_INT( s, accept(s, addr, &socklen) ); + *addrlen = socklen; +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + int crc = -1, prc = -1; + threadEntry_t self; + fdEntry_t* fdEntry = getFdEntry(s); + + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* On AIX, when the system call connect() is interrupted, the connection + * is not aborted and it will be established asynchronously by the kernel. + * Hence, no need to restart connect() when EINTR is received + */ + startOp(fdEntry, &self); + crc = connect(s, addr, addrlen); + endOp(fdEntry, &self); + + if (crc == -1 && errno == EINTR) { + struct pollfd s_pollfd; + int sockopt_arg = 0; + socklen_t len; + + s_pollfd.fd = s; + s_pollfd.events = POLLOUT | POLLERR; + + /* poll the file descriptor */ + do { + startOp(fdEntry, &self); + prc = poll(&s_pollfd, 1, -1); + endOp(fdEntry, &self); + } while (prc == -1 && errno == EINTR); + + if (prc < 0) + return prc; + + len = sizeof(sockopt_arg); + + /* Check whether the connection has been established */ + if (getsockopt(s, SOL_SOCKET, SO_ERROR, &sockopt_arg, &len) == -1) + return -1; + + if (sockopt_arg != 0 ) { + errno = sockopt_arg; + return -1; + } + } else { + return crc; + } + + /* At this point, fd is connected. Set successful return code */ + return 0; +} + +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); +} + +/* + * Wrapper for poll(s, timeout). + * Auto restarts with adjusted timeout if interrupted by + * signal other than our wakeup signal. + */ +int NET_Timeout(int s, long timeout) { + long prevtime = 0, newtime; + struct timeval t; + fdEntry_t *fdEntry = getFdEntry(s); + + /* + * Check that fd hasn't been closed. + */ + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Pick up current time as may need to adjust timeout + */ + if (timeout > 0) { + gettimeofday(&t, NULL); + prevtime = t.tv_sec * 1000 + t.tv_usec / 1000; + } + + for(;;) { + struct pollfd pfd; + int rv; + threadEntry_t self; + + /* + * Poll the fd. If interrupted by our wakeup signal + * errno will be set to EBADF. + */ + pfd.fd = s; + pfd.events = POLLIN | POLLERR; + + startOp(fdEntry, &self); + rv = poll(&pfd, 1, timeout); + endOp(fdEntry, &self); + + /* + * If interrupted then adjust timeout. If timeout + * has expired return 0 (indicating timeout expired). + */ + if (rv < 0 && errno == EINTR) { + if (timeout > 0) { + gettimeofday(&t, NULL); + newtime = t.tv_sec * 1000 + t.tv_usec / 1000; + timeout -= newtime - prevtime; + if (timeout <= 0) { + return 0; + } + prevtime = newtime; + } + } else { + return rv; + } + + } +}
--- a/jdk/src/java.base/aix/native/libnet/java/net/aix_close.c Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,491 +0,0 @@ -/* - * Copyright (c) 2001, 2013, 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. - */ - -/* - * This file contains implementations of NET_... functions. The NET_.. functions are - * wrappers for common file- and socket functions plus provisions for non-blocking IO. - * - * (basically, the layers remember all file descriptors waiting for a particular fd; - * all threads waiting on a certain fd can be woken up by sending them a signal; this - * is done e.g. when the fd is closed.) - * - * This was originally copied from the linux_close.c implementation. - * - * Side Note: This coding needs initialization. Under Linux this is done - * automatically via __attribute((constructor)), on AIX this is done manually - * (see aix_close_init). - * - */ - -/* - AIX needs a workaround for I/O cancellation, see: - http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm - ... - The close subroutine is blocked until all subroutines which use the file - descriptor return to usr space. For example, when a thread is calling close - and another thread is calling select with the same file descriptor, the - close subroutine does not return until the select call returns. - ... -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <pthread.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <sys/poll.h> - -/* - * Stack allocated by thread when doing blocking operation - */ -typedef struct threadEntry { - pthread_t thr; /* this thread */ - struct threadEntry *next; /* next thread */ - int intr; /* interrupted */ -} threadEntry_t; - -/* - * Heap allocated during initialized - one entry per fd - */ -typedef struct { - pthread_mutex_t lock; /* fd lock */ - threadEntry_t *threads; /* threads blocked on fd */ -} fdEntry_t; - -/* - * Signal to unblock thread - */ -static int sigWakeup = (SIGRTMAX - 1); - -/* - * The fd table and the number of file descriptors - */ -static fdEntry_t *fdTable = NULL; -static int fdCount = 0; - -/* - * Null signal handler - */ -static void sig_wakeup(int sig) { -} - -/* - * Initialization routine (executed when library is loaded) - * Allocate fd tables and sets up signal handler. - * - * On AIX we don't have __attribute((constructor)) so we need to initialize - * manually (from JNI_OnLoad() in 'src/share/native/java/net/net_util.c') - */ -void aix_close_init() { - struct rlimit nbr_files; - sigset_t sigset; - struct sigaction sa; - - /* Check already initialized */ - if (fdCount > 0 && fdTable != NULL) { - return; - } - - /* - * Allocate table based on the maximum number of - * file descriptors. - */ - if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { - fprintf(stderr, "library initialization failed - " - "unable to get max # of allocated fds\n"); - abort(); - } - fdCount = nbr_files.rlim_max; - /* - * We have a conceptual problem here, when the number of files is - * unlimited. As a kind of workaround, we ensure the table is big - * enough for handle even a large number of files. Since SAP itself - * recommends a limit of 32000 files, we just use 64000 as 'infinity'. - */ - if (nbr_files.rlim_max == RLIM_INFINITY) { - fdCount = 64000; - } - fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); - if (fdTable == NULL) { - fprintf(stderr, "library initialization failed - " - "unable to allocate file descriptor table - out of memory"); - abort(); - } - - { - int i; - for (i=0; i < fdCount; i++) { - pthread_mutex_init(&fdTable[i].lock, NULL); - } - } - - /* - * Setup the signal handler - */ - sa.sa_handler = sig_wakeup; - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - sigaction(sigWakeup, &sa, NULL); - - sigemptyset(&sigset); - sigaddset(&sigset, sigWakeup); - sigprocmask(SIG_UNBLOCK, &sigset, NULL); -} - -/* - * Return the fd table for this fd or NULL is fd out - * of range. - */ -static inline fdEntry_t *getFdEntry(int fd) -{ - if (fd < 0 || fd >= fdCount) { - return NULL; - } - return &fdTable[fd]; -} - -/* - * Start a blocking operation :- - * Insert thread onto thread list for the fd. - */ -static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) -{ - self->thr = pthread_self(); - self->intr = 0; - - pthread_mutex_lock(&(fdEntry->lock)); - { - self->next = fdEntry->threads; - fdEntry->threads = self; - } - pthread_mutex_unlock(&(fdEntry->lock)); -} - -/* - * End a blocking operation :- - * Remove thread from thread list for the fd - * If fd has been interrupted then set errno to EBADF - */ -static inline void endOp - (fdEntry_t *fdEntry, threadEntry_t *self) -{ - int orig_errno = errno; - pthread_mutex_lock(&(fdEntry->lock)); - { - threadEntry_t *curr, *prev=NULL; - curr = fdEntry->threads; - while (curr != NULL) { - if (curr == self) { - if (curr->intr) { - orig_errno = EBADF; - } - if (prev == NULL) { - fdEntry->threads = curr->next; - } else { - prev->next = curr->next; - } - break; - } - prev = curr; - curr = curr->next; - } - } - pthread_mutex_unlock(&(fdEntry->lock)); - errno = orig_errno; -} - -/* - * Close or dup2 a file descriptor ensuring that all threads blocked on - * the file descriptor are notified via a wakeup signal. - * - * fd1 < 0 => close(fd2) - * fd1 >= 0 => dup2(fd1, fd2) - * - * Returns -1 with errno set if operation fails. - */ -static int closefd(int fd1, int fd2) { - int rv, orig_errno; - fdEntry_t *fdEntry = getFdEntry(fd2); - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* - * Lock the fd to hold-off additional I/O on this fd. - */ - pthread_mutex_lock(&(fdEntry->lock)); - - { - /* On fast machines we see that we enter dup2 before the - * accepting thread had a chance to get and process the signal. - * So in case we woke a thread up, give it some time to cope. - * Also see https://bugs.openjdk.java.net/browse/JDK-8006395 */ - int num_woken = 0; - - /* - * Send a wakeup signal to all threads blocked on this - * file descriptor. - */ - threadEntry_t *curr = fdEntry->threads; - while (curr != NULL) { - curr->intr = 1; - pthread_kill( curr->thr, sigWakeup ); - num_woken ++; - curr = curr->next; - } - - if (num_woken > 0) { - usleep(num_woken * 50); - } - - /* - * And close/dup the file descriptor - * (restart if interrupted by signal) - */ - do { - if (fd1 < 0) { - rv = close(fd2); - } else { - rv = dup2(fd1, fd2); - } - } while (rv == -1 && errno == EINTR); - } - - /* - * Unlock without destroying errno - */ - orig_errno = errno; - pthread_mutex_unlock(&(fdEntry->lock)); - errno = orig_errno; - - return rv; -} - -/* - * Wrapper for dup2 - same semantics as dup2 system call except - * that any threads blocked in an I/O system call on fd2 will be - * preempted and return -1/EBADF; - */ -int NET_Dup2(int fd, int fd2) { - if (fd < 0) { - errno = EBADF; - return -1; - } - return closefd(fd, fd2); -} - -/* - * Wrapper for close - same semantics as close system call - * except that any threads blocked in an I/O on fd will be - * preempted and the I/O system call will return -1/EBADF. - */ -int NET_SocketClose(int fd) { - return closefd(-1, fd); -} - -/************** Basic I/O operations here ***************/ - -/* - * Macro to perform a blocking IO operation. Restarts - * automatically if interrupted by signal (other than - * our wakeup signal) - */ -#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ - int ret; \ - threadEntry_t self; \ - fdEntry_t *fdEntry = getFdEntry(FD); \ - if (fdEntry == NULL) { \ - errno = EBADF; \ - return -1; \ - } \ - do { \ - startOp(fdEntry, &self); \ - ret = FUNC; \ - endOp(fdEntry, &self); \ - } while (ret == -1 && errno == EINTR); \ - return ret; \ -} - -int NET_Read(int s, void* buf, size_t len) { - BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); -} - -int NET_ReadV(int s, const struct iovec * vector, int count) { - BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); -} - -int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, - struct sockaddr *from, int *fromlen) { - socklen_t socklen = *fromlen; - BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, &socklen) ); - *fromlen = socklen; -} - -int NET_Send(int s, void *msg, int len, unsigned int flags) { - BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); -} - -int NET_WriteV(int s, const struct iovec * vector, int count) { - BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); -} - -int NET_SendTo(int s, const void *msg, int len, unsigned int - flags, const struct sockaddr *to, int tolen) { - BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); -} - -int NET_Accept(int s, struct sockaddr *addr, int *addrlen) { - socklen_t socklen = *addrlen; - BLOCKING_IO_RETURN_INT( s, accept(s, addr, &socklen) ); - *addrlen = socklen; -} - -int NET_Connect(int s, struct sockaddr *addr, int addrlen) { - int crc = -1, prc = -1; - threadEntry_t self; - fdEntry_t* fdEntry = getFdEntry(s); - - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* On AIX, when the system call connect() is interrupted, the connection - * is not aborted and it will be established asynchronously by the kernel. - * Hence, no need to restart connect() when EINTR is received - */ - startOp(fdEntry, &self); - crc = connect(s, addr, addrlen); - endOp(fdEntry, &self); - - if (crc == -1 && errno == EINTR) { - struct pollfd s_pollfd; - int sockopt_arg = 0; - socklen_t len; - - s_pollfd.fd = s; - s_pollfd.events = POLLOUT | POLLERR; - - /* poll the file descriptor */ - do { - startOp(fdEntry, &self); - prc = poll(&s_pollfd, 1, -1); - endOp(fdEntry, &self); - } while (prc == -1 && errno == EINTR); - - if (prc < 0) - return prc; - - len = sizeof(sockopt_arg); - - /* Check whether the connection has been established */ - if (getsockopt(s, SOL_SOCKET, SO_ERROR, &sockopt_arg, &len) == -1) - return -1; - - if (sockopt_arg != 0 ) { - errno = sockopt_arg; - return -1; - } - } else { - return crc; - } - - /* At this point, fd is connected. Set successful return code */ - return 0; -} - -int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { - BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); -} - -/* - * Wrapper for poll(s, timeout). - * Auto restarts with adjusted timeout if interrupted by - * signal other than our wakeup signal. - */ -int NET_Timeout(int s, long timeout) { - long prevtime = 0, newtime; - struct timeval t; - fdEntry_t *fdEntry = getFdEntry(s); - - /* - * Check that fd hasn't been closed. - */ - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* - * Pick up current time as may need to adjust timeout - */ - if (timeout > 0) { - gettimeofday(&t, NULL); - prevtime = t.tv_sec * 1000 + t.tv_usec / 1000; - } - - for(;;) { - struct pollfd pfd; - int rv; - threadEntry_t self; - - /* - * Poll the fd. If interrupted by our wakeup signal - * errno will be set to EBADF. - */ - pfd.fd = s; - pfd.events = POLLIN | POLLERR; - - startOp(fdEntry, &self); - rv = poll(&pfd, 1, timeout); - endOp(fdEntry, &self); - - /* - * If interrupted then adjust timeout. If timeout - * has expired return 0 (indicating timeout expired). - */ - if (rv < 0 && errno == EINTR) { - if (timeout > 0) { - gettimeofday(&t, NULL); - newtime = t.tv_sec * 1000 + t.tv_usec / 1000; - timeout -= newtime - prevtime; - if (timeout <= 0) { - return 0; - } - prevtime = newtime; - } - } else { - return rv; - } - - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/linux/native/libnet/linux_close.c Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2001, 2013, 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/uio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/poll.h> + +/* + * Stack allocated by thread when doing blocking operation + */ +typedef struct threadEntry { + pthread_t thr; /* this thread */ + struct threadEntry *next; /* next thread */ + int intr; /* interrupted */ +} threadEntry_t; + +/* + * Heap allocated during initialized - one entry per fd + */ +typedef struct { + pthread_mutex_t lock; /* fd lock */ + threadEntry_t *threads; /* threads blocked on fd */ +} fdEntry_t; + +/* + * Signal to unblock thread + */ +static int sigWakeup = (__SIGRTMAX - 2); + +/* + * The fd table and the number of file descriptors + */ +static fdEntry_t *fdTable; +static int fdCount; + +/* + * Null signal handler + */ +static void sig_wakeup(int sig) { +} + +/* + * Initialization routine (executed when library is loaded) + * Allocate fd tables and sets up signal handler. + */ +static void __attribute((constructor)) init() { + struct rlimit nbr_files; + sigset_t sigset; + struct sigaction sa; + + /* + * Allocate table based on the maximum number of + * file descriptors. + */ + getrlimit(RLIMIT_NOFILE, &nbr_files); + fdCount = nbr_files.rlim_max; + fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + if (fdTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor table - out of memory"); + abort(); + } + + /* + * Setup the signal handler + */ + sa.sa_handler = sig_wakeup; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sigWakeup, &sa, NULL); + + sigemptyset(&sigset); + sigaddset(&sigset, sigWakeup); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); +} + +/* + * Return the fd table for this fd or NULL is fd out + * of range. + */ +static inline fdEntry_t *getFdEntry(int fd) +{ + if (fd < 0 || fd >= fdCount) { + return NULL; + } + return &fdTable[fd]; +} + +/* + * Start a blocking operation :- + * Insert thread onto thread list for the fd. + */ +static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) +{ + self->thr = pthread_self(); + self->intr = 0; + + pthread_mutex_lock(&(fdEntry->lock)); + { + self->next = fdEntry->threads; + fdEntry->threads = self; + } + pthread_mutex_unlock(&(fdEntry->lock)); +} + +/* + * End a blocking operation :- + * Remove thread from thread list for the fd + * If fd has been interrupted then set errno to EBADF + */ +static inline void endOp + (fdEntry_t *fdEntry, threadEntry_t *self) +{ + int orig_errno = errno; + pthread_mutex_lock(&(fdEntry->lock)); + { + threadEntry_t *curr, *prev=NULL; + curr = fdEntry->threads; + while (curr != NULL) { + if (curr == self) { + if (curr->intr) { + orig_errno = EBADF; + } + if (prev == NULL) { + fdEntry->threads = curr->next; + } else { + prev->next = curr->next; + } + break; + } + prev = curr; + curr = curr->next; + } + } + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; +} + +/* + * Close or dup2 a file descriptor ensuring that all threads blocked on + * the file descriptor are notified via a wakeup signal. + * + * fd1 < 0 => close(fd2) + * fd1 >= 0 => dup2(fd1, fd2) + * + * Returns -1 with errno set if operation fails. + */ +static int closefd(int fd1, int fd2) { + int rv, orig_errno; + fdEntry_t *fdEntry = getFdEntry(fd2); + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Lock the fd to hold-off additional I/O on this fd. + */ + pthread_mutex_lock(&(fdEntry->lock)); + + { + /* + * And close/dup the file descriptor + * (restart if interrupted by signal) + */ + do { + if (fd1 < 0) { + rv = close(fd2); + } else { + rv = dup2(fd1, fd2); + } + } while (rv == -1 && errno == EINTR); + + /* + * Send a wakeup signal to all threads blocked on this + * file descriptor. + */ + threadEntry_t *curr = fdEntry->threads; + while (curr != NULL) { + curr->intr = 1; + pthread_kill( curr->thr, sigWakeup ); + curr = curr->next; + } + } + + /* + * Unlock without destroying errno + */ + orig_errno = errno; + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; + + return rv; +} + +/* + * Wrapper for dup2 - same semantics as dup2 system call except + * that any threads blocked in an I/O system call on fd2 will be + * preempted and return -1/EBADF; + */ +int NET_Dup2(int fd, int fd2) { + if (fd < 0) { + errno = EBADF; + return -1; + } + return closefd(fd, fd2); +} + +/* + * Wrapper for close - same semantics as close system call + * except that any threads blocked in an I/O on fd will be + * preempted and the I/O system call will return -1/EBADF. + */ +int NET_SocketClose(int fd) { + return closefd(-1, fd); +} + +/************** Basic I/O operations here ***************/ + +/* + * Macro to perform a blocking IO operation. Restarts + * automatically if interrupted by signal (other than + * our wakeup signal) + */ +#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ + int ret; \ + threadEntry_t self; \ + fdEntry_t *fdEntry = getFdEntry(FD); \ + if (fdEntry == NULL) { \ + errno = EBADF; \ + return -1; \ + } \ + do { \ + startOp(fdEntry, &self); \ + ret = FUNC; \ + endOp(fdEntry, &self); \ + } while (ret == -1 && errno == EINTR); \ + return ret; \ +} + +int NET_Read(int s, void* buf, size_t len) { + BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); +} + +int NET_ReadV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen) { + BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) ); +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); +} + +int NET_WriteV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int + flags, const struct sockaddr *to, int tolen) { + BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); +} + +int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) ); +} + +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); +} + +/* + * Wrapper for poll(s, timeout). + * Auto restarts with adjusted timeout if interrupted by + * signal other than our wakeup signal. + */ +int NET_Timeout(int s, long timeout) { + long prevtime = 0, newtime; + struct timeval t; + fdEntry_t *fdEntry = getFdEntry(s); + + /* + * Check that fd hasn't been closed. + */ + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Pick up current time as may need to adjust timeout + */ + if (timeout > 0) { + gettimeofday(&t, NULL); + prevtime = t.tv_sec * 1000 + t.tv_usec / 1000; + } + + for(;;) { + struct pollfd pfd; + int rv; + threadEntry_t self; + + /* + * Poll the fd. If interrupted by our wakeup signal + * errno will be set to EBADF. + */ + pfd.fd = s; + pfd.events = POLLIN | POLLERR; + + startOp(fdEntry, &self); + rv = poll(&pfd, 1, timeout); + endOp(fdEntry, &self); + + /* + * If interrupted then adjust timeout. If timeout + * has expired return 0 (indicating timeout expired). + */ + if (rv < 0 && errno == EINTR) { + if (timeout > 0) { + gettimeofday(&t, NULL); + newtime = t.tv_sec * 1000 + t.tv_usec / 1000; + timeout -= newtime - prevtime; + if (timeout <= 0) { + return 0; + } + prevtime = newtime; + } + } else { + return rv; + } + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/macosx/native/libjava/java_props_macosx.c Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,349 @@ +/* + * Copyright (c) 1998, 2013, 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. + */ + +#include <dlfcn.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <Security/AuthSession.h> +#include <CoreFoundation/CoreFoundation.h> +#include <SystemConfiguration/SystemConfiguration.h> +#include <Foundation/Foundation.h> + +#include "java_props_macosx.h" + + +// need dlopen/dlsym trick to avoid pulling in JavaRuntimeSupport before libjava.dylib is loaded +static void *getJRSFramework() { + static void *jrsFwk = NULL; + if (jrsFwk == NULL) { + jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL); + } + return jrsFwk; +} + +char *getPosixLocale(int cat) { + char *lc = setlocale(cat, NULL); + if ((lc == NULL) || (strcmp(lc, "C") == 0)) { + lc = getenv("LANG"); + } + if (lc == NULL) return NULL; + return strdup(lc); +} + +#define LOCALEIDLENGTH 128 +char *getMacOSXLocale(int cat) { + switch (cat) { + case LC_MESSAGES: + { + void *jrsFwk = getJRSFramework(); + if (jrsFwk == NULL) return NULL; + + char *(*JRSCopyPrimaryLanguage)() = dlsym(jrsFwk, "JRSCopyPrimaryLanguage"); + char *primaryLanguage = JRSCopyPrimaryLanguage ? JRSCopyPrimaryLanguage() : NULL; + if (primaryLanguage == NULL) return NULL; + + char *(*JRSCopyCanonicalLanguageForPrimaryLanguage)(char *) = dlsym(jrsFwk, "JRSCopyCanonicalLanguageForPrimaryLanguage"); + char *canonicalLanguage = JRSCopyCanonicalLanguageForPrimaryLanguage ? JRSCopyCanonicalLanguageForPrimaryLanguage(primaryLanguage) : NULL; + free (primaryLanguage); + + return canonicalLanguage; + } + break; + default: + { + char localeString[LOCALEIDLENGTH]; + if (CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()), + localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding())) { + return strdup(localeString); + } + } + break; + } + + return NULL; +} + +char *setupMacOSXLocale(int cat) { + char * ret = getMacOSXLocale(cat); + + if (cat == LC_MESSAGES && ret != NULL) { + void *jrsFwk = getJRSFramework(); + if (jrsFwk != NULL) { + void (*JRSSetDefaultLocalization)(char *) = dlsym(jrsFwk, "JRSSetDefaultLocalization"); + if (JRSSetDefaultLocalization) JRSSetDefaultLocalization(ret); + } + } + + if (ret == NULL) { + return getPosixLocale(cat); + } else { + return ret; + } +} + +int isInAquaSession() { + // environment variable to bypass the aqua session check + char *ev = getenv("AWT_FORCE_HEADFUL"); + if (ev && (strncasecmp(ev, "true", 4) == 0)) { + // if "true" then tell the caller we're in an Aqua session without actually checking + return 1; + } + // Is the WindowServer available? + SecuritySessionId session_id; + SessionAttributeBits session_info; + OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info); + if (status == noErr) { + if (session_info & sessionHasGraphicAccess) { + return 1; + } + } + return 0; +} + +void setOSNameAndVersion(java_props_t *sprops) { + /* Don't rely on JRSCopyOSName because there's no guarantee the value will + * remain the same, or even if the JRS functions will continue to be part of + * Mac OS X. So hardcode os_name, and fill in os_version if we can. + */ + sprops->os_name = strdup("Mac OS X"); + + void *jrsFwk = getJRSFramework(); + if (jrsFwk != NULL) { + char *(*copyOSVersion)() = dlsym(jrsFwk, "JRSCopyOSVersion"); + if (copyOSVersion != NULL) { + sprops->os_version = copyOSVersion(); + return; + } + } + sprops->os_version = strdup("Unknown"); +} + + +static Boolean getProxyInfoForProtocol(CFDictionaryRef inDict, CFStringRef inEnabledKey, CFStringRef inHostKey, CFStringRef inPortKey, CFStringRef *outProxyHost, int *ioProxyPort) { + /* See if the proxy is enabled. */ + CFNumberRef cf_enabled = CFDictionaryGetValue(inDict, inEnabledKey); + if (cf_enabled == NULL) { + return false; + } + + int isEnabled = false; + if (!CFNumberGetValue(cf_enabled, kCFNumberIntType, &isEnabled)) { + return isEnabled; + } + + if (!isEnabled) return false; + *outProxyHost = CFDictionaryGetValue(inDict, inHostKey); + + // If cf_host is null, that means the checkbox is set, + // but no host was entered. We'll treat that as NOT ENABLED. + // If cf_port is null or cf_port isn't a number, that means + // no port number was entered. Treat this as ENABLED with the + // protocol's default port. + if (*outProxyHost == NULL) { + return false; + } + + if (CFStringGetLength(*outProxyHost) == 0) { + return false; + } + + int newPort = 0; + CFNumberRef cf_port = NULL; + if ((cf_port = CFDictionaryGetValue(inDict, inPortKey)) != NULL && + CFNumberGetValue(cf_port, kCFNumberIntType, &newPort) && + newPort > 0) { + *ioProxyPort = newPort; + } else { + // bad port or no port - leave *ioProxyPort unchanged + } + + return true; +} + +static char *createUTF8CString(const CFStringRef theString) { + if (theString == NULL) return NULL; + + const CFIndex stringLength = CFStringGetLength(theString); + const CFIndex bufSize = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 1; + char *returnVal = (char *)malloc(bufSize); + + if (CFStringGetCString(theString, returnVal, bufSize, kCFStringEncodingUTF8)) { + return returnVal; + } + + free(returnVal); + return NULL; +} + +// Return TRUE if str is a syntactically valid IP address. +// Using inet_pton() instead of inet_aton() for IPv6 support. +// len is only a hint; cstr must still be nul-terminated +static int looksLikeIPAddress(char *cstr, size_t len) { + if (len == 0 || (len == 1 && cstr[0] == '.')) return FALSE; + + char dst[16]; // big enough for INET6 + return (1 == inet_pton(AF_INET, cstr, dst) || + 1 == inet_pton(AF_INET6, cstr, dst)); +} + + + +// Convert Mac OS X proxy exception entry to Java syntax. +// See Radar #3441134 for details. +// Returns NULL if this exception should be ignored by Java. +// May generate a string with multiple exceptions separated by '|'. +static char * createConvertedException(CFStringRef cf_original) { + // This is done with char* instead of CFString because inet_pton() + // needs a C string. + char *c_exception = createUTF8CString(cf_original); + if (!c_exception) return NULL; + + int c_len = strlen(c_exception); + + // 1. sanitize exception prefix + if (c_len >= 1 && 0 == strncmp(c_exception, ".", 1)) { + memmove(c_exception, c_exception+1, c_len); + c_len -= 1; + } else if (c_len >= 2 && 0 == strncmp(c_exception, "*.", 2)) { + memmove(c_exception, c_exception+2, c_len-1); + c_len -= 2; + } + + // 2. pre-reject other exception wildcards + if (strchr(c_exception, '*')) { + free(c_exception); + return NULL; + } + + // 3. no IP wildcarding + if (looksLikeIPAddress(c_exception, c_len)) { + return c_exception; + } + + // 4. allow domain suffixes + // c_exception is now "str\0" - change to "str|*.str\0" + c_exception = reallocf(c_exception, c_len+3+c_len+1); + if (!c_exception) return NULL; + + strncpy(c_exception+c_len, "|*.", 3); + strncpy(c_exception+c_len+3, c_exception, c_len); + c_exception[c_len+3+c_len] = '\0'; + return c_exception; +} + +/* + * Method for fetching the user.home path and storing it in the property list. + * For signed .apps running in the Mac App Sandbox, user.home is set to the + * app's sandbox container. + */ +void setUserHome(java_props_t *sprops) { + if (sprops == NULL) { return; } + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + sprops->user_home = createUTF8CString((CFStringRef)NSHomeDirectory()); + [pool drain]; +} + +/* + * Method for fetching proxy info and storing it in the property list. + */ +void setProxyProperties(java_props_t *sProps) { + if (sProps == NULL) return; + + char buf[16]; /* Used for %d of an int - 16 is plenty */ + CFStringRef + cf_httpHost = NULL, + cf_httpsHost = NULL, + cf_ftpHost = NULL, + cf_socksHost = NULL, + cf_gopherHost = NULL; + int + httpPort = 80, // Default proxy port values + httpsPort = 443, + ftpPort = 21, + socksPort = 1080, + gopherPort = 70; + + CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL); + if (dict == NULL) return; + + /* Read the proxy exceptions list */ + CFArrayRef cf_list = CFDictionaryGetValue(dict, kSCPropNetProxiesExceptionsList); + + CFMutableStringRef cf_exceptionList = NULL; + if (cf_list != NULL) { + CFIndex len = CFArrayGetCount(cf_list), idx; + + cf_exceptionList = CFStringCreateMutable(NULL, 0); + for (idx = (CFIndex)0; idx < len; idx++) { + CFStringRef cf_ehost; + if ((cf_ehost = CFArrayGetValueAtIndex(cf_list, idx))) { + /* Convert this exception from Mac OS X syntax to Java syntax. + See Radar #3441134 for details. This may generate a string + with multiple Java exceptions separated by '|'. */ + char *c_exception = createConvertedException(cf_ehost); + if (c_exception) { + /* Append the host to the list of exclusions. */ + if (CFStringGetLength(cf_exceptionList) > 0) { + CFStringAppendCString(cf_exceptionList, "|", kCFStringEncodingMacRoman); + } + CFStringAppendCString(cf_exceptionList, c_exception, kCFStringEncodingMacRoman); + free(c_exception); + } + } + } + } + + if (cf_exceptionList != NULL) { + if (CFStringGetLength(cf_exceptionList) > 0) { + sProps->exceptionList = createUTF8CString(cf_exceptionList); + } + CFRelease(cf_exceptionList); + } + +#define CHECK_PROXY(protocol, PROTOCOL) \ + sProps->protocol##ProxyEnabled = \ + getProxyInfoForProtocol(dict, kSCPropNetProxies##PROTOCOL##Enable, \ + kSCPropNetProxies##PROTOCOL##Proxy, \ + kSCPropNetProxies##PROTOCOL##Port, \ + &cf_##protocol##Host, &protocol##Port); \ + if (sProps->protocol##ProxyEnabled) { \ + sProps->protocol##Host = createUTF8CString(cf_##protocol##Host); \ + snprintf(buf, sizeof(buf), "%d", protocol##Port); \ + sProps->protocol##Port = malloc(strlen(buf) + 1); \ + strcpy(sProps->protocol##Port, buf); \ + } + + CHECK_PROXY(http, HTTP); + CHECK_PROXY(https, HTTPS); + CHECK_PROXY(ftp, FTP); + CHECK_PROXY(socks, SOCKS); + CHECK_PROXY(gopher, Gopher); + +#undef CHECK_PROXY + + CFRelease(dict); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/macosx/native/libjava/java_props_macosx.h Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1998, 2013, 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. + */ + +#include "java_props.h" + +char *setupMacOSXLocale(int cat); +void setOSNameAndVersion(java_props_t *sprops); +void setUserHome(java_props_t *sprops); +void setProxyProperties(java_props_t *sProps); +int isInAquaSession();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/macosx/native/libnet/bsd_close.c Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2001, 2012, 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/param.h> +#include <signal.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/uio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/poll.h> + +/* + * Stack allocated by thread when doing blocking operation + */ +typedef struct threadEntry { + pthread_t thr; /* this thread */ + struct threadEntry *next; /* next thread */ + int intr; /* interrupted */ +} threadEntry_t; + +/* + * Heap allocated during initialized - one entry per fd + */ +typedef struct { + pthread_mutex_t lock; /* fd lock */ + threadEntry_t *threads; /* threads blocked on fd */ +} fdEntry_t; + +/* + * Signal to unblock thread + */ +static int sigWakeup = SIGIO; + +/* + * The fd table and the number of file descriptors + */ +static fdEntry_t *fdTable; +static int fdCount; + +/* + * This limit applies if getlimit() returns unlimited. + * Unfortunately, this means if someone wants a higher limit + * then they have to set an explicit limit, higher than this, + * which is probably counter-intuitive. + */ +#define MAX_FD_COUNT 4096 + +/* + * Null signal handler + */ +static void sig_wakeup(int sig) { +} + +/* + * Initialization routine (executed when library is loaded) + * Allocate fd tables and sets up signal handler. + */ +static void __attribute((constructor)) init() { + struct rlimit nbr_files; + sigset_t sigset; + struct sigaction sa; + int i; + + /* + * Allocate table based on the maximum number of + * file descriptors. + */ + getrlimit(RLIMIT_NOFILE, &nbr_files); + if (nbr_files.rlim_max == RLIM_INFINITY) { + fdCount = MAX_FD_COUNT; + } else { + fdCount = nbr_files.rlim_max; + } + fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + if (fdTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor table - out of memory"); + abort(); + } + for (i=0; i<fdCount; i++) { + pthread_mutex_init(&fdTable[i].lock, NULL); + } + + /* + * Setup the signal handler + */ + sa.sa_handler = sig_wakeup; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sigWakeup, &sa, NULL); + + sigemptyset(&sigset); + sigaddset(&sigset, sigWakeup); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); +} + +/* + * Return the fd table for this fd or NULL is fd out + * of range. + */ +static inline fdEntry_t *getFdEntry(int fd) +{ + if (fd < 0 || fd >= fdCount) { + return NULL; + } + return &fdTable[fd]; +} + +/* + * Start a blocking operation :- + * Insert thread onto thread list for the fd. + */ +static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) +{ + self->thr = pthread_self(); + self->intr = 0; + + pthread_mutex_lock(&(fdEntry->lock)); + { + self->next = fdEntry->threads; + fdEntry->threads = self; + } + pthread_mutex_unlock(&(fdEntry->lock)); +} + +/* + * End a blocking operation :- + * Remove thread from thread list for the fd + * If fd has been interrupted then set errno to EBADF + */ +static inline void endOp + (fdEntry_t *fdEntry, threadEntry_t *self) +{ + int orig_errno = errno; + pthread_mutex_lock(&(fdEntry->lock)); + { + threadEntry_t *curr, *prev=NULL; + curr = fdEntry->threads; + while (curr != NULL) { + if (curr == self) { + if (curr->intr) { + orig_errno = EBADF; + } + if (prev == NULL) { + fdEntry->threads = curr->next; + } else { + prev->next = curr->next; + } + break; + } + prev = curr; + curr = curr->next; + } + } + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; +} + +/* + * Close or dup2 a file descriptor ensuring that all threads blocked on + * the file descriptor are notified via a wakeup signal. + * + * fd1 < 0 => close(fd2) + * fd1 >= 0 => dup2(fd1, fd2) + * + * Returns -1 with errno set if operation fails. + */ +static int closefd(int fd1, int fd2) { + int rv, orig_errno; + fdEntry_t *fdEntry = getFdEntry(fd2); + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Lock the fd to hold-off additional I/O on this fd. + */ + pthread_mutex_lock(&(fdEntry->lock)); + + { + /* + * Send a wakeup signal to all threads blocked on this + * file descriptor. + */ + threadEntry_t *curr = fdEntry->threads; + while (curr != NULL) { + curr->intr = 1; + pthread_kill( curr->thr, sigWakeup ); + curr = curr->next; + } + + /* + * And close/dup the file descriptor + * (restart if interrupted by signal) + */ + do { + if (fd1 < 0) { + rv = close(fd2); + } else { + rv = dup2(fd1, fd2); + } + } while (rv == -1 && errno == EINTR); + + } + + /* + * Unlock without destroying errno + */ + orig_errno = errno; + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; + + return rv; +} + +/* + * Wrapper for dup2 - same semantics as dup2 system call except + * that any threads blocked in an I/O system call on fd2 will be + * preempted and return -1/EBADF; + */ +int NET_Dup2(int fd, int fd2) { + if (fd < 0) { + errno = EBADF; + return -1; + } + return closefd(fd, fd2); +} + +/* + * Wrapper for close - same semantics as close system call + * except that any threads blocked in an I/O on fd will be + * preempted and the I/O system call will return -1/EBADF. + */ +int NET_SocketClose(int fd) { + return closefd(-1, fd); +} + +/************** Basic I/O operations here ***************/ + +/* + * Macro to perform a blocking IO operation. Restarts + * automatically if interrupted by signal (other than + * our wakeup signal) + */ +#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ + int ret; \ + threadEntry_t self; \ + fdEntry_t *fdEntry = getFdEntry(FD); \ + if (fdEntry == NULL) { \ + errno = EBADF; \ + return -1; \ + } \ + do { \ + startOp(fdEntry, &self); \ + ret = FUNC; \ + endOp(fdEntry, &self); \ + } while (ret == -1 && errno == EINTR); \ + return ret; \ +} + +int NET_Read(int s, void* buf, size_t len) { + BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); +} + +int NET_ReadV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen) { + BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) ); +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); +} + +int NET_WriteV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int + flags, const struct sockaddr *to, int tolen) { + BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); +} + +int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) ); +} + +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); +} + +/* + * Wrapper for select(s, timeout). We are using select() on Mac OS due to Bug 7131399. + * Auto restarts with adjusted timeout if interrupted by + * signal other than our wakeup signal. + */ +int NET_Timeout(int s, long timeout) { + long prevtime = 0, newtime; + struct timeval t, *tp = &t; + fd_set fds; + fd_set* fdsp = NULL; + int allocated = 0; + threadEntry_t self; + fdEntry_t *fdEntry = getFdEntry(s); + + /* + * Check that fd hasn't been closed. + */ + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Pick up current time as may need to adjust timeout + */ + if (timeout > 0) { + /* Timed */ + struct timeval now; + gettimeofday(&now, NULL); + prevtime = now.tv_sec * 1000 + now.tv_usec / 1000; + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + } else if (timeout < 0) { + /* Blocking */ + tp = 0; + } else { + /* Poll */ + t.tv_sec = 0; + t.tv_usec = 0; + } + + if (s < FD_SETSIZE) { + fdsp = &fds; + FD_ZERO(fdsp); + } else { + int length = (howmany(s+1, NFDBITS)) * sizeof(int); + fdsp = (fd_set *) calloc(1, length); + if (fdsp == NULL) { + return -1; // errno will be set to ENOMEM + } + allocated = 1; + } + FD_SET(s, fdsp); + + for(;;) { + int rv; + + /* + * call select on the fd. If interrupted by our wakeup signal + * errno will be set to EBADF. + */ + + startOp(fdEntry, &self); + rv = select(s+1, fdsp, 0, 0, tp); + endOp(fdEntry, &self); + + /* + * If interrupted then adjust timeout. If timeout + * has expired return 0 (indicating timeout expired). + */ + if (rv < 0 && errno == EINTR) { + if (timeout > 0) { + struct timeval now; + gettimeofday(&now, NULL); + newtime = now.tv_sec * 1000 + now.tv_usec / 1000; + timeout -= newtime - prevtime; + if (timeout <= 0) { + if (allocated != 0) + free(fdsp); + return 0; + } + prevtime = newtime; + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + } + } else { + if (allocated != 0) + free(fdsp); + return rv; + } + + } +}
--- a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -27,6 +27,9 @@ import sun.misc.FloatingDecimal; import java.util.Arrays; +import java.util.Spliterator; +import java.util.stream.IntStream; +import java.util.stream.StreamSupport; /** * A mutable sequence of characters. @@ -292,7 +295,7 @@ if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) { throw new IndexOutOfBoundsException(); } - return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex); + return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex); } /** @@ -1432,6 +1435,34 @@ public abstract String toString(); /** + * {@inheritDoc} + * @since 1.9 + */ + @Override + public IntStream chars() { + // Reuse String-based spliterator. This requires a supplier to + // capture the value and count when the terminal operation is executed + return StreamSupport.intStream( + () -> new String.IntCharArraySpliterator(value, 0, count, 0), + Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED, + false); + } + + /** + * {@inheritDoc} + * @since 1.9 + */ + @Override + public IntStream codePoints() { + // Reuse String-based spliterator. This requires a supplier to + // capture the value and count when the terminal operation is executed + return StreamSupport.intStream( + () -> new String.CodePointsSpliterator(value, 0, count, 0), + Spliterator.ORDERED, + false); + } + + /** * Needed by {@code String} for the contentEquals method. */ final char[] getValue() {
--- a/jdk/src/java.base/share/classes/java/lang/Object.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/Object.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2015, 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 @@ -86,12 +86,11 @@ * for unequal objects may improve the performance of hash tables. * </ul> * <p> - * As much as is reasonably practical, the hashCode method defined by - * class {@code Object} does return distinct integers for distinct - * objects. (This is typically implemented by converting the internal - * address of the object into an integer, but this implementation - * technique is not required by the - * Java™ programming language.) + * As much as is reasonably practical, the hashCode method defined + * by class {@code Object} does return distinct integers for + * distinct objects. (The hashCode may or may not be implemented + * as some function of an object's memory address at some point + * in time.) * * @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) @@ -344,10 +343,12 @@ * ... // Perform action appropriate to condition * } * </pre> - * (For more information on this topic, see Section 3.2.3 in Doug Lea's - * "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, - * 2000), or Item 50 in Joshua Bloch's "Effective Java Programming - * Language Guide" (Addison-Wesley, 2001). + * + * (For more information on this topic, see section 14.2, + * Condition Queues, in Brian Goetz and others' "Java Concurrency + * in Practice" (Addison-Wesley, 2006) or Item 69 in Joshua + * Bloch's "Effective Java (Second Edition)" (Addison-Wesley, + * 2008). * * <p>If the current thread is {@linkplain java.lang.Thread#interrupt() * interrupted} by any thread before or while it is waiting, then an
--- a/jdk/src/java.base/share/classes/java/lang/String.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/String.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2015, 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 @@ -34,10 +34,14 @@ import java.util.Formatter; import java.util.Locale; import java.util.Objects; +import java.util.Spliterator; import java.util.StringJoiner; +import java.util.function.IntConsumer; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import java.util.stream.IntStream; +import java.util.stream.StreamSupport; /** * The {@code String} class represents character strings. All @@ -2894,6 +2898,180 @@ return this; } + static class IntCharArraySpliterator implements Spliterator.OfInt { + private final char[] array; + private int index; // current index, modified on advance/split + private final int fence; // one past last index + private final int cs; + + IntCharArraySpliterator(char[] array, int acs) { + this(array, 0, array.length, acs); + } + + IntCharArraySpliterator(char[] array, int origin, int fence, int acs) { + this.array = array; + this.index = origin; + this.fence = fence; + this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED + | Spliterator.SUBSIZED; + } + + @Override + public OfInt trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) + ? null + : new IntCharArraySpliterator(array, lo, index = mid, cs); + } + + @Override + public void forEachRemaining(IntConsumer action) { + char[] a; int i, hi; // hoist accesses and checks from loop + if (action == null) + throw new NullPointerException(); + if ((a = array).length >= (hi = fence) && + (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(IntConsumer action) { + if (action == null) + throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + + @Override + public long estimateSize() { return (long)(fence - index); } + + @Override + public int characteristics() { + return cs; + } + } + + /** + * Returns a stream of {@code int} zero-extending the {@code char} values + * from this sequence. Any char which maps to a <a + * href="{@docRoot}/java/lang/Character.html#unicode">surrogate code + * point</a> is passed through uninterpreted. + * + * @return an IntStream of char values from this sequence + * @since 1.9 + */ + @Override + public IntStream chars() { + return StreamSupport.intStream( + new IntCharArraySpliterator(value, Spliterator.IMMUTABLE), false); + } + + static class CodePointsSpliterator implements Spliterator.OfInt { + private final char[] array; + private int index; // current index, modified on advance/split + private final int fence; // one past last index + private final int cs; + + CodePointsSpliterator(char[] array, int acs) { + this(array, 0, array.length, acs); + } + + CodePointsSpliterator(char[] array, int origin, int fence, int acs) { + this.array = array; + this.index = origin; + this.fence = fence; + this.cs = acs | Spliterator.ORDERED; + } + + @Override + public OfInt trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + if (lo >= mid) + return null; + + int midOneLess; + // If the mid-point intersects a surrogate pair + if (Character.isLowSurrogate(array[mid]) && + Character.isHighSurrogate(array[midOneLess = (mid -1)])) { + // If there is only one pair it cannot be split + if (lo >= midOneLess) + return null; + // Shift the mid-point to align with the surrogate pair + return new CodePointsSpliterator(array, lo, index = midOneLess, cs); + } + return new CodePointsSpliterator(array, lo, index = mid, cs); + } + + @Override + public void forEachRemaining(IntConsumer action) { + char[] a; int i, hi; // hoist accesses and checks from loop + if (action == null) + throw new NullPointerException(); + if ((a = array).length >= (hi = fence) && + (i = index) >= 0 && i < (index = hi)) { + do { + i = advance(a, i, hi, action); + } while (i < hi); + } + } + + @Override + public boolean tryAdvance(IntConsumer action) { + if (action == null) + throw new NullPointerException(); + if (index >= 0 && index < fence) { + index = advance(array, index, fence, action); + return true; + } + return false; + } + + // Advance one code point from the index, i, and return the next + // index to advance from + private static int advance(char[] a, int i, int hi, IntConsumer action) { + char c1 = a[i++]; + int cp = c1; + if (Character.isHighSurrogate(c1) && i < hi) { + char c2 = a[i]; + if (Character.isLowSurrogate(c2)) { + i++; + cp = Character.toCodePoint(c1, c2); + } + } + action.accept(cp); + return i; + } + + @Override + public long estimateSize() { return (long)(fence - index); } + + @Override + public int characteristics() { + return cs; + } + } + + /** + * Returns a stream of code point values from this sequence. Any surrogate + * pairs encountered in the sequence are combined as if by {@linkplain + * Character#toCodePoint Character.toCodePoint} and the result is passed + * to the stream. Any other code units, including ordinary BMP characters, + * unpaired surrogates, and undefined code units, are zero-extended to + * {@code int} values which are then passed to the stream. + * + * @return an IntStream of Unicode code points from this sequence + * @since 1.9 + */ + @Override + public IntStream codePoints() { + return StreamSupport.intStream( + new CodePointsSpliterator(value, Spliterator.IMMUTABLE), false); + } + /** * Converts this string to a new character array. *
--- a/jdk/src/java.base/share/classes/java/lang/System.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/System.java Thu Jan 29 15:35:29 2015 -0800 @@ -376,19 +376,16 @@ * the difference between two such values, obtained within the same * instance of a Java virtual machine, is computed. * - * <p> For example, to measure how long some code takes to execute: - * <pre> {@code + * <p>For example, to measure how long some code takes to execute: + * <pre> {@code * long startTime = System.nanoTime(); * // ... the code being measured ... - * long estimatedTime = System.nanoTime() - startTime;}</pre> + * long elapsedNanos = System.nanoTime() - startTime;}</pre> * - * <p>To compare two nanoTime values - * <pre> {@code - * long t0 = System.nanoTime(); - * ... - * long t1 = System.nanoTime();}</pre> - * - * one should use {@code t1 - t0 < 0}, not {@code t1 < t0}, + * <p>To compare elapsed time against a timeout, use <pre> {@code + * if (System.nanoTime() - startTime >= timeoutNanos) ...}</pre> + * instead of <pre> {@code + * if (System.nanoTime() >= startTime + timeoutNanos) ...}</pre> * because of the possibility of numerical overflow. * * @return the current value of the running Java Virtual Machine's
--- a/jdk/src/java.base/share/classes/java/util/Spliterator.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/util/Spliterator.java Thu Jan 29 15:35:29 2015 -0800 @@ -553,6 +553,12 @@ * sub-split size is known and additions or removals to the source are not * reflected when traversing. * + * <p>A top-level Spliterator should not report both {@code CONCURRENT} and + * {@code IMMUTABLE}, since they are mutually exclusive. Such a Spliterator + * is inconsistent and no guarantees can be made about any computation using + * that Spliterator. Sub-spliterators may report {@code IMMUTABLE} if + * additions or removals to the source are not reflected when traversing. + * * @apiNote Most concurrent collections maintain a consistency policy * guaranteeing accuracy with respect to elements present at the point of * Spliterator construction, but possibly not reflecting subsequent
--- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, 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 @@ -845,22 +845,6 @@ public native Object allocateInstance(Class<?> cls) throws InstantiationException; - /** Lock the object. It must get unlocked via {@link #monitorExit}. */ - public native void monitorEnter(Object o); - - /** - * Unlock the object. It must have been locked via {@link - * #monitorEnter}. - */ - public native void monitorExit(Object o); - - /** - * Tries to lock the object. Returns true or false to indicate - * whether the lock succeeded. If it did, the object must be - * unlocked via {@link #monitorExit}. - */ - public native boolean tryMonitorEnter(Object o); - /** Throw the exception without telling the verifier. */ public native void throwException(Throwable ee);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/solaris/native/libnet/solaris_close.c Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 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. + */ + +#include <errno.h> +#include <sys/socket.h> +#include <stropts.h> +#include <unistd.h> + +/* Support for restartable system calls on Solaris. */ + +#define RESTARTABLE_RETURN_INT(_cmd) do { \ + int _result; \ + if (1) { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ + return _result; \ + } \ +} while(0) + +int NET_Read(int s, void* buf, size_t len) { + RESTARTABLE_RETURN_INT(recv(s, buf, len, 0)); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen) { + RESTARTABLE_RETURN_INT(recvfrom(s, buf, len, flags, from, fromlen)); +} + +int NET_ReadV(int s, const struct iovec * vector, int count) { + RESTARTABLE_RETURN_INT(readv(s, vector, count)); +} + +int NET_WriteV(int s, const struct iovec * vector, int count) { + RESTARTABLE_RETURN_INT(writev(s, vector, count)); +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + RESTARTABLE_RETURN_INT(send(s, msg, len, flags)); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int flags, + const struct sockaddr *to, int tolen) { + RESTARTABLE_RETURN_INT(sendto(s, msg, len, flags, to, tolen)); +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + RESTARTABLE_RETURN_INT(connect(s, addr, addrlen)); +} + +int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + RESTARTABLE_RETURN_INT(accept(s, addr, addrlen)); +} + +int NET_SocketClose(int fd) { + return close(fd); +} + +int NET_Dup2(int fd, int fd2) { + return dup2(fd, fd2); +} + +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + RESTARTABLE_RETURN_INT(poll(ufds, nfds, timeout)); +} + +int NET_Timeout(int s, long timeout) { + int result; + struct timeval t; + long prevtime, newtime; + struct pollfd pfd; + pfd.fd = s; + pfd.events = POLLIN; + + if (timeout > 0) { + gettimeofday(&t, NULL); + prevtime = (t.tv_sec * 1000) + t.tv_usec / 1000; + } + + for(;;) { + result = poll(&pfd, 1, timeout); + if (result < 0 && errno == EINTR) { + if (timeout > 0) { + gettimeofday(&t, NULL); + newtime = (t.tv_sec * 1000) + t.tv_usec /1000; + timeout -= newtime - prevtime; + if (timeout <= 0) + return 0; + prevtime = newtime; + } + } else { + return result; + } + } +}
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -25,24 +25,156 @@ package java.lang; -import java.io.IOException; +import java.lang.ProcessBuilder.Redirect; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.lang.ProcessBuilder.Redirect; -import java.lang.ProcessBuilder.Redirect; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Locale; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.security.AccessController; +import static java.security.AccessController.doPrivileged; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; /** - * This class is for the exclusive use of ProcessBuilder.start() to - * create new processes. + * This java.lang.Process subclass in the UNIX environment is for the exclusive use of + * ProcessBuilder.start() to create new processes. * + * @author Mario Wolczko and Ross Knippel. + * @author Konstantin Kladko (ported to Linux and Bsd) * @author Martin Buchholz + * @author Volker Simonis (ported to AIX) * @since 1.5 */ -final class ProcessImpl { +final class ProcessImpl extends Process { private static final sun.misc.JavaIOFileDescriptorAccess fdAccess = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess(); - private ProcessImpl() {} // Not instantiable + private final int pid; + private int exitcode; + private boolean hasExited; + + private /* final */ OutputStream stdin; + private /* final */ InputStream stdout; + private /* final */ InputStream stderr; + + // only used on Solaris + private /* final */ DeferredCloseInputStream stdout_inner_stream; + + private static enum LaunchMechanism { + // order IS important! + FORK, + POSIX_SPAWN, + VFORK + } + + private static enum Platform { + + LINUX(LaunchMechanism.VFORK, LaunchMechanism.FORK), + + BSD(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK), + + SOLARIS(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK), + + AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK); + + final LaunchMechanism defaultLaunchMechanism; + final Set<LaunchMechanism> validLaunchMechanisms; + + Platform(LaunchMechanism ... launchMechanisms) { + this.defaultLaunchMechanism = launchMechanisms[0]; + this.validLaunchMechanisms = + EnumSet.copyOf(Arrays.asList(launchMechanisms)); + } + + @SuppressWarnings("fallthrough") + private String helperPath(String javahome, String osArch) { + switch (this) { + case SOLARIS: + if (osArch.equals("x86")) { osArch = "i386"; } + else if (osArch.equals("x86_64")) { osArch = "amd64"; } + // fall through... + case LINUX: + case AIX: + return javahome + "/lib/" + osArch + "/jspawnhelper"; + + case BSD: + return javahome + "/lib/jspawnhelper"; + + default: + throw new AssertionError("Unsupported platform: " + this); + } + } + + String helperPath() { + return AccessController.doPrivileged( + (PrivilegedAction<String>) () -> + helperPath(System.getProperty("java.home"), + System.getProperty("os.arch")) + ); + } + + LaunchMechanism launchMechanism() { + return AccessController.doPrivileged( + (PrivilegedAction<LaunchMechanism>) () -> { + String s = System.getProperty( + "jdk.lang.Process.launchMechanism"); + LaunchMechanism lm; + if (s == null) { + lm = defaultLaunchMechanism; + s = lm.name().toLowerCase(Locale.ENGLISH); + } else { + try { + lm = LaunchMechanism.valueOf( + s.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { + lm = null; + } + } + if (lm == null || !validLaunchMechanisms.contains(lm)) { + throw new Error( + s + " is not a supported " + + "process launch mechanism on this platform." + ); + } + return lm; + } + ); + } + + static Platform get() { + String osName = AccessController.doPrivileged( + (PrivilegedAction<String>) () -> System.getProperty("os.name") + ); + + if (osName.equals("Linux")) { return LINUX; } + if (osName.contains("OS X")) { return BSD; } + if (osName.equals("SunOS")) { return SOLARIS; } + if (osName.equals("AIX")) { return AIX; } + + throw new Error(osName + " is not a supported OS platform."); + } + } + + private static final Platform platform = Platform.get(); + private static final LaunchMechanism launchMechanism = platform.launchMechanism(); + private static final byte[] helperpath = toCString(platform.helperPath()); + + /* this is for the reaping thread */ + private native int waitForProcessExit(int pid); private static byte[] toCString(String s) { if (s == null) @@ -50,8 +182,8 @@ byte[] bytes = s.getBytes(); byte[] result = new byte[bytes.length + 1]; System.arraycopy(bytes, 0, - result, 0, - bytes.length); + result, 0, + bytes.length); result[result.length-1] = (byte)0; return result; } @@ -62,7 +194,7 @@ String dir, ProcessBuilder.Redirect[] redirects, boolean redirectErrorStream) - throws IOException + throws IOException { assert cmdarray != null && cmdarray.length > 0; @@ -112,7 +244,7 @@ std_fds[1] = 1; else { f1 = new FileOutputStream(redirects[1].file(), - redirects[1].append()); + redirects[1].append()); std_fds[1] = fdAccess.get(f1.getFD()); } @@ -122,18 +254,18 @@ std_fds[2] = 2; else { f2 = new FileOutputStream(redirects[2].file(), - redirects[2].append()); + redirects[2].append()); std_fds[2] = fdAccess.get(f2.getFD()); } } - return new UNIXProcess - (toCString(cmdarray[0]), - argBlock, args.length, - envBlock, envc[0], - toCString(dir), - std_fds, - redirectErrorStream); + return new ProcessImpl + (toCString(cmdarray[0]), + argBlock, args.length, + envBlock, envc[0], + toCString(dir), + std_fds, + redirectErrorStream); } finally { // In theory, close() can throw IOException // (although it is rather unlikely to happen here) @@ -144,4 +276,654 @@ } } } + + + /** + * Creates a process. Depending on the {@code mode} flag, this is done by + * one of the following mechanisms: + * <pre> + * 1 - fork(2) and exec(2) + * 2 - posix_spawn(3P) + * 3 - vfork(2) and exec(2) + * + * (4 - clone(2) and exec(2) - obsolete and currently disabled in native code) + * </pre> + * @param fds an array of three file descriptors. + * Indexes 0, 1, and 2 correspond to standard input, + * standard output and standard error, respectively. On + * input, a value of -1 means to create a pipe to connect + * child and parent processes. On output, a value which + * is not -1 is the parent pipe fd corresponding to the + * pipe which has been created. An element of this array + * is -1 on input if and only if it is <em>not</em> -1 on + * output. + * @return the pid of the subprocess + */ + private native int forkAndExec(int mode, byte[] helperpath, + byte[] prog, + byte[] argBlock, int argc, + byte[] envBlock, int envc, + byte[] dir, + int[] fds, + boolean redirectErrorStream) + throws IOException; + + /** + * The thread pool of "process reaper" daemon threads. + */ + private static final Executor processReaperExecutor = + doPrivileged((PrivilegedAction<Executor>) () -> { + + ThreadGroup tg = Thread.currentThread().getThreadGroup(); + while (tg.getParent() != null) tg = tg.getParent(); + ThreadGroup systemThreadGroup = tg; + + ThreadFactory threadFactory = grimReaper -> { + // Our thread stack requirement is quite modest. + Thread t = new Thread(systemThreadGroup, grimReaper, + "process reaper", 32768); + t.setDaemon(true); + // A small attempt (probably futile) to avoid priority inversion + t.setPriority(Thread.MAX_PRIORITY); + return t; + }; + + return Executors.newCachedThreadPool(threadFactory); + }); + + private ProcessImpl(final byte[] prog, + final byte[] argBlock, final int argc, + final byte[] envBlock, final int envc, + final byte[] dir, + final int[] fds, + final boolean redirectErrorStream) + throws IOException { + + pid = forkAndExec(launchMechanism.ordinal() + 1, + helperpath, + prog, + argBlock, argc, + envBlock, envc, + dir, + fds, + redirectErrorStream); + + try { + doPrivileged((PrivilegedExceptionAction<Void>) () -> { + initStreams(fds); + return null; + }); + } catch (PrivilegedActionException ex) { + throw (IOException) ex.getException(); + } + } + + static FileDescriptor newFileDescriptor(int fd) { + FileDescriptor fileDescriptor = new FileDescriptor(); + fdAccess.set(fileDescriptor, fd); + return fileDescriptor; + } + + void initStreams(int[] fds) throws IOException { + switch (platform) { + case LINUX: + case BSD: + stdin = (fds[0] == -1) ? + ProcessBuilder.NullOutputStream.INSTANCE : + new ProcessPipeOutputStream(fds[0]); + + stdout = (fds[1] == -1) ? + ProcessBuilder.NullInputStream.INSTANCE : + new ProcessPipeInputStream(fds[1]); + + stderr = (fds[2] == -1) ? + ProcessBuilder.NullInputStream.INSTANCE : + new ProcessPipeInputStream(fds[2]); + + processReaperExecutor.execute(() -> { + int exitcode = waitForProcessExit(pid); + + synchronized (this) { + this.exitcode = exitcode; + this.hasExited = true; + this.notifyAll(); + } + + if (stdout instanceof ProcessPipeInputStream) + ((ProcessPipeInputStream) stdout).processExited(); + + if (stderr instanceof ProcessPipeInputStream) + ((ProcessPipeInputStream) stderr).processExited(); + + if (stdin instanceof ProcessPipeOutputStream) + ((ProcessPipeOutputStream) stdin).processExited(); + }); + break; + + case SOLARIS: + stdin = (fds[0] == -1) ? + ProcessBuilder.NullOutputStream.INSTANCE : + new BufferedOutputStream( + new FileOutputStream(newFileDescriptor(fds[0]))); + + stdout = (fds[1] == -1) ? + ProcessBuilder.NullInputStream.INSTANCE : + new BufferedInputStream( + stdout_inner_stream = + new DeferredCloseInputStream( + newFileDescriptor(fds[1]))); + + stderr = (fds[2] == -1) ? + ProcessBuilder.NullInputStream.INSTANCE : + new DeferredCloseInputStream(newFileDescriptor(fds[2])); + + /* + * For each subprocess forked a corresponding reaper task + * is submitted. That task is the only thread which waits + * for the subprocess to terminate and it doesn't hold any + * locks while doing so. This design allows waitFor() and + * exitStatus() to be safely executed in parallel (and they + * need no native code). + */ + processReaperExecutor.execute(() -> { + int exitcode = waitForProcessExit(pid); + + synchronized (this) { + this.exitcode = exitcode; + this.hasExited = true; + this.notifyAll(); + } + }); + break; + + case AIX: + stdin = (fds[0] == -1) ? + ProcessBuilder.NullOutputStream.INSTANCE : + new ProcessPipeOutputStream(fds[0]); + + stdout = (fds[1] == -1) ? + ProcessBuilder.NullInputStream.INSTANCE : + new DeferredCloseProcessPipeInputStream(fds[1]); + + stderr = (fds[2] == -1) ? + ProcessBuilder.NullInputStream.INSTANCE : + new DeferredCloseProcessPipeInputStream(fds[2]); + + processReaperExecutor.execute(() -> { + int exitcode = waitForProcessExit(pid); + + synchronized (this) { + this.exitcode = exitcode; + this.hasExited = true; + this.notifyAll(); + } + + if (stdout instanceof DeferredCloseProcessPipeInputStream) + ((DeferredCloseProcessPipeInputStream) stdout).processExited(); + + if (stderr instanceof DeferredCloseProcessPipeInputStream) + ((DeferredCloseProcessPipeInputStream) stderr).processExited(); + + if (stdin instanceof ProcessPipeOutputStream) + ((ProcessPipeOutputStream) stdin).processExited(); + }); + break; + + default: throw new AssertionError("Unsupported platform: " + platform); + } + } + + public OutputStream getOutputStream() { + return stdin; + } + + public InputStream getInputStream() { + return stdout; + } + + public InputStream getErrorStream() { + return stderr; + } + + public synchronized int waitFor() throws InterruptedException { + while (!hasExited) { + wait(); + } + return exitcode; + } + + @Override + public synchronized boolean waitFor(long timeout, TimeUnit unit) + throws InterruptedException + { + if (hasExited) return true; + if (timeout <= 0) return false; + + long remainingNanos = unit.toNanos(timeout); + long deadline = System.nanoTime() + remainingNanos; + + do { + // Round up to next millisecond + wait(TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L)); + if (hasExited) { + return true; + } + remainingNanos = deadline - System.nanoTime(); + } while (remainingNanos > 0); + return hasExited; + } + + public synchronized int exitValue() { + if (!hasExited) { + throw new IllegalThreadStateException("process hasn't exited"); + } + return exitcode; + } + + private static native void destroyProcess(int pid, boolean force); + + private void destroy(boolean force) { + switch (platform) { + case LINUX: + case BSD: + case AIX: + // There is a risk that pid will be recycled, causing us to + // kill the wrong process! So we only terminate processes + // that appear to still be running. Even with this check, + // there is an unavoidable race condition here, but the window + // is very small, and OSes try hard to not recycle pids too + // soon, so this is quite safe. + synchronized (this) { + if (!hasExited) + destroyProcess(pid, force); + } + try { stdin.close(); } catch (IOException ignored) {} + try { stdout.close(); } catch (IOException ignored) {} + try { stderr.close(); } catch (IOException ignored) {} + break; + + case SOLARIS: + // There is a risk that pid will be recycled, causing us to + // kill the wrong process! So we only terminate processes + // that appear to still be running. Even with this check, + // there is an unavoidable race condition here, but the window + // is very small, and OSes try hard to not recycle pids too + // soon, so this is quite safe. + synchronized (this) { + if (!hasExited) + destroyProcess(pid, force); + try { + stdin.close(); + if (stdout_inner_stream != null) + stdout_inner_stream.closeDeferred(stdout); + if (stderr instanceof DeferredCloseInputStream) + ((DeferredCloseInputStream) stderr) + .closeDeferred(stderr); + } catch (IOException e) { + // ignore + } + } + break; + + default: throw new AssertionError("Unsupported platform: " + platform); + } + } + + public void destroy() { + destroy(false); + } + + @Override + public Process destroyForcibly() { + destroy(true); + return this; + } + + @Override + public long getPid() { + return pid; + } + + @Override + public synchronized boolean isAlive() { + return !hasExited; + } + + private static native void init(); + + static { + init(); + } + + /** + * A buffered input stream for a subprocess pipe file descriptor + * that allows the underlying file descriptor to be reclaimed when + * the process exits, via the processExited hook. + * + * This is tricky because we do not want the user-level InputStream to be + * closed until the user invokes close(), and we need to continue to be + * able to read any buffered data lingering in the OS pipe buffer. + */ + private static class ProcessPipeInputStream extends BufferedInputStream { + private final Object closeLock = new Object(); + + ProcessPipeInputStream(int fd) { + super(new FileInputStream(newFileDescriptor(fd))); + } + private static byte[] drainInputStream(InputStream in) + throws IOException { + int n = 0; + int j; + byte[] a = null; + while ((j = in.available()) > 0) { + a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j); + n += in.read(a, n, j); + } + return (a == null || n == a.length) ? a : Arrays.copyOf(a, n); + } + + /** Called by the process reaper thread when the process exits. */ + synchronized void processExited() { + synchronized (closeLock) { + try { + InputStream in = this.in; + // this stream is closed if and only if: in == null + if (in != null) { + byte[] stragglers = drainInputStream(in); + in.close(); + this.in = (stragglers == null) ? + ProcessBuilder.NullInputStream.INSTANCE : + new ByteArrayInputStream(stragglers); + } + } catch (IOException ignored) {} + } + } + + @Override + public void close() throws IOException { + // BufferedInputStream#close() is not synchronized unlike most other + // methods. Synchronizing helps avoid race with processExited(). + synchronized (closeLock) { + super.close(); + } + } + } + + /** + * A buffered output stream for a subprocess pipe file descriptor + * that allows the underlying file descriptor to be reclaimed when + * the process exits, via the processExited hook. + */ + private static class ProcessPipeOutputStream extends BufferedOutputStream { + ProcessPipeOutputStream(int fd) { + super(new FileOutputStream(newFileDescriptor(fd))); + } + + /** Called by the process reaper thread when the process exits. */ + synchronized void processExited() { + OutputStream out = this.out; + if (out != null) { + try { + out.close(); + } catch (IOException ignored) { + // We know of no reason to get an IOException, but if + // we do, there's nothing else to do but carry on. + } + this.out = ProcessBuilder.NullOutputStream.INSTANCE; + } + } + } + + // A FileInputStream that supports the deferment of the actual close + // operation until the last pending I/O operation on the stream has + // finished. This is required on Solaris because we must close the stdin + // and stdout streams in the destroy method in order to reclaim the + // underlying file descriptors. Doing so, however, causes any thread + // currently blocked in a read on one of those streams to receive an + // IOException("Bad file number"), which is incompatible with historical + // behavior. By deferring the close we allow any pending reads to see -1 + // (EOF) as they did before. + // + private static class DeferredCloseInputStream extends FileInputStream + { + DeferredCloseInputStream(FileDescriptor fd) { + super(fd); + } + + private Object lock = new Object(); // For the following fields + private boolean closePending = false; + private int useCount = 0; + private InputStream streamToClose; + + private void raise() { + synchronized (lock) { + useCount++; + } + } + + private void lower() throws IOException { + synchronized (lock) { + useCount--; + if (useCount == 0 && closePending) { + streamToClose.close(); + } + } + } + + // stc is the actual stream to be closed; it might be this object, or + // it might be an upstream object for which this object is downstream. + // + private void closeDeferred(InputStream stc) throws IOException { + synchronized (lock) { + if (useCount == 0) { + stc.close(); + } else { + closePending = true; + streamToClose = stc; + } + } + } + + public void close() throws IOException { + synchronized (lock) { + useCount = 0; + closePending = false; + } + super.close(); + } + + public int read() throws IOException { + raise(); + try { + return super.read(); + } finally { + lower(); + } + } + + public int read(byte[] b) throws IOException { + raise(); + try { + return super.read(b); + } finally { + lower(); + } + } + + public int read(byte[] b, int off, int len) throws IOException { + raise(); + try { + return super.read(b, off, len); + } finally { + lower(); + } + } + + public long skip(long n) throws IOException { + raise(); + try { + return super.skip(n); + } finally { + lower(); + } + } + + public int available() throws IOException { + raise(); + try { + return super.available(); + } finally { + lower(); + } + } + } + + /** + * A buffered input stream for a subprocess pipe file descriptor + * that allows the underlying file descriptor to be reclaimed when + * the process exits, via the processExited hook. + * + * This is tricky because we do not want the user-level InputStream to be + * closed until the user invokes close(), and we need to continue to be + * able to read any buffered data lingering in the OS pipe buffer. + * + * On AIX this is especially tricky, because the 'close()' system call + * will block if another thread is at the same time blocked in a file + * operation (e.g. 'read()') on the same file descriptor. We therefore + * combine 'ProcessPipeInputStream' approach used on Linux and Bsd + * with the DeferredCloseInputStream approach used on Solaris. This means + * that every potentially blocking operation on the file descriptor + * increments a counter before it is executed and decrements it once it + * finishes. The 'close()' operation will only be executed if there are + * no pending operations. Otherwise it is deferred after the last pending + * operation has finished. + * + */ + private static class DeferredCloseProcessPipeInputStream + extends BufferedInputStream { + + private final Object closeLock = new Object(); + private int useCount = 0; + private boolean closePending = false; + + DeferredCloseProcessPipeInputStream(int fd) { + super(new FileInputStream(newFileDescriptor(fd))); + } + + private InputStream drainInputStream(InputStream in) + throws IOException { + int n = 0; + int j; + byte[] a = null; + synchronized (closeLock) { + if (buf == null) // asynchronous close()? + return null; // discard + j = in.available(); + } + while (j > 0) { + a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j); + synchronized (closeLock) { + if (buf == null) // asynchronous close()? + return null; // discard + n += in.read(a, n, j); + j = in.available(); + } + } + return (a == null) ? + ProcessBuilder.NullInputStream.INSTANCE : + new ByteArrayInputStream(n == a.length ? a : Arrays.copyOf(a, n)); + } + + /** Called by the process reaper thread when the process exits. */ + synchronized void processExited() { + try { + InputStream in = this.in; + if (in != null) { + InputStream stragglers = drainInputStream(in); + in.close(); + this.in = stragglers; + } + } catch (IOException ignored) { } + } + + private void raise() { + synchronized (closeLock) { + useCount++; + } + } + + private void lower() throws IOException { + synchronized (closeLock) { + useCount--; + if (useCount == 0 && closePending) { + closePending = false; + super.close(); + } + } + } + + @Override + public int read() throws IOException { + raise(); + try { + return super.read(); + } finally { + lower(); + } + } + + @Override + public int read(byte[] b) throws IOException { + raise(); + try { + return super.read(b); + } finally { + lower(); + } + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + raise(); + try { + return super.read(b, off, len); + } finally { + lower(); + } + } + + @Override + public long skip(long n) throws IOException { + raise(); + try { + return super.skip(n); + } finally { + lower(); + } + } + + @Override + public int available() throws IOException { + raise(); + try { + return super.available(); + } finally { + lower(); + } + } + + @Override + public void close() throws IOException { + // BufferedInputStream#close() is not synchronized unlike most other + // methods. Synchronizing helps avoid racing with drainInputStream(). + synchronized (closeLock) { + if (useCount == 0) { + super.close(); + } + else { + closePending = true; + } + } + } + } }
--- a/jdk/src/java.base/unix/classes/java/lang/UNIXProcess.java Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,836 +0,0 @@ -/* - * Copyright (c) 1995, 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. - */ - -package java.lang; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.Executor; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.security.AccessController; -import static java.security.AccessController.doPrivileged; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; - -/** - * java.lang.Process subclass in the UNIX environment. - * - * @author Mario Wolczko and Ross Knippel. - * @author Konstantin Kladko (ported to Linux and Bsd) - * @author Martin Buchholz - * @author Volker Simonis (ported to AIX) - */ -final class UNIXProcess extends Process { - private static final sun.misc.JavaIOFileDescriptorAccess fdAccess - = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess(); - - private final int pid; - private int exitcode; - private boolean hasExited; - - private /* final */ OutputStream stdin; - private /* final */ InputStream stdout; - private /* final */ InputStream stderr; - - // only used on Solaris - private /* final */ DeferredCloseInputStream stdout_inner_stream; - - private static enum LaunchMechanism { - // order IS important! - FORK, - POSIX_SPAWN, - VFORK - } - - private static enum Platform { - - LINUX(LaunchMechanism.VFORK, LaunchMechanism.FORK), - - BSD(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK), - - SOLARIS(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK), - - AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK); - - final LaunchMechanism defaultLaunchMechanism; - final Set<LaunchMechanism> validLaunchMechanisms; - - Platform(LaunchMechanism ... launchMechanisms) { - this.defaultLaunchMechanism = launchMechanisms[0]; - this.validLaunchMechanisms = - EnumSet.copyOf(Arrays.asList(launchMechanisms)); - } - - @SuppressWarnings("fallthrough") - private String helperPath(String javahome, String osArch) { - switch (this) { - case SOLARIS: - if (osArch.equals("x86")) { osArch = "i386"; } - else if (osArch.equals("x86_64")) { osArch = "amd64"; } - // fall through... - case LINUX: - case AIX: - return javahome + "/lib/" + osArch + "/jspawnhelper"; - - case BSD: - return javahome + "/lib/jspawnhelper"; - - default: - throw new AssertionError("Unsupported platform: " + this); - } - } - - String helperPath() { - return AccessController.doPrivileged( - (PrivilegedAction<String>) () -> - helperPath(System.getProperty("java.home"), - System.getProperty("os.arch")) - ); - } - - LaunchMechanism launchMechanism() { - return AccessController.doPrivileged( - (PrivilegedAction<LaunchMechanism>) () -> { - String s = System.getProperty( - "jdk.lang.Process.launchMechanism"); - LaunchMechanism lm; - if (s == null) { - lm = defaultLaunchMechanism; - s = lm.name().toLowerCase(Locale.ENGLISH); - } else { - try { - lm = LaunchMechanism.valueOf( - s.toUpperCase(Locale.ENGLISH)); - } catch (IllegalArgumentException e) { - lm = null; - } - } - if (lm == null || !validLaunchMechanisms.contains(lm)) { - throw new Error( - s + " is not a supported " + - "process launch mechanism on this platform." - ); - } - return lm; - } - ); - } - - static Platform get() { - String osName = AccessController.doPrivileged( - (PrivilegedAction<String>) () -> System.getProperty("os.name") - ); - - if (osName.equals("Linux")) { return LINUX; } - if (osName.contains("OS X")) { return BSD; } - if (osName.equals("SunOS")) { return SOLARIS; } - if (osName.equals("AIX")) { return AIX; } - - throw new Error(osName + " is not a supported OS platform."); - } - } - - private static final Platform platform = Platform.get(); - private static final LaunchMechanism launchMechanism = platform.launchMechanism(); - private static final byte[] helperpath = toCString(platform.helperPath()); - - private static byte[] toCString(String s) { - if (s == null) - return null; - byte[] bytes = s.getBytes(); - byte[] result = new byte[bytes.length + 1]; - System.arraycopy(bytes, 0, - result, 0, - bytes.length); - result[result.length-1] = (byte)0; - return result; - } - - /* this is for the reaping thread */ - private native int waitForProcessExit(int pid); - - /** - * Creates a process. Depending on the {@code mode} flag, this is done by - * one of the following mechanisms: - * <pre> - * 1 - fork(2) and exec(2) - * 2 - posix_spawn(3P) - * 3 - vfork(2) and exec(2) - * - * (4 - clone(2) and exec(2) - obsolete and currently disabled in native code) - * </pre> - * @param fds an array of three file descriptors. - * Indexes 0, 1, and 2 correspond to standard input, - * standard output and standard error, respectively. On - * input, a value of -1 means to create a pipe to connect - * child and parent processes. On output, a value which - * is not -1 is the parent pipe fd corresponding to the - * pipe which has been created. An element of this array - * is -1 on input if and only if it is <em>not</em> -1 on - * output. - * @return the pid of the subprocess - */ - private native int forkAndExec(int mode, byte[] helperpath, - byte[] prog, - byte[] argBlock, int argc, - byte[] envBlock, int envc, - byte[] dir, - int[] fds, - boolean redirectErrorStream) - throws IOException; - - /** - * The thread pool of "process reaper" daemon threads. - */ - private static final Executor processReaperExecutor = - doPrivileged((PrivilegedAction<Executor>) () -> { - - ThreadGroup tg = Thread.currentThread().getThreadGroup(); - while (tg.getParent() != null) tg = tg.getParent(); - ThreadGroup systemThreadGroup = tg; - - ThreadFactory threadFactory = grimReaper -> { - // Our thread stack requirement is quite modest. - Thread t = new Thread(systemThreadGroup, grimReaper, - "process reaper", 32768); - t.setDaemon(true); - // A small attempt (probably futile) to avoid priority inversion - t.setPriority(Thread.MAX_PRIORITY); - return t; - }; - - return Executors.newCachedThreadPool(threadFactory); - }); - - UNIXProcess(final byte[] prog, - final byte[] argBlock, final int argc, - final byte[] envBlock, final int envc, - final byte[] dir, - final int[] fds, - final boolean redirectErrorStream) - throws IOException { - - pid = forkAndExec(launchMechanism.ordinal() + 1, - helperpath, - prog, - argBlock, argc, - envBlock, envc, - dir, - fds, - redirectErrorStream); - - try { - doPrivileged((PrivilegedExceptionAction<Void>) () -> { - initStreams(fds); - return null; - }); - } catch (PrivilegedActionException ex) { - throw (IOException) ex.getException(); - } - } - - static FileDescriptor newFileDescriptor(int fd) { - FileDescriptor fileDescriptor = new FileDescriptor(); - fdAccess.set(fileDescriptor, fd); - return fileDescriptor; - } - - void initStreams(int[] fds) throws IOException { - switch (platform) { - case LINUX: - case BSD: - stdin = (fds[0] == -1) ? - ProcessBuilder.NullOutputStream.INSTANCE : - new ProcessPipeOutputStream(fds[0]); - - stdout = (fds[1] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new ProcessPipeInputStream(fds[1]); - - stderr = (fds[2] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new ProcessPipeInputStream(fds[2]); - - processReaperExecutor.execute(() -> { - int exitcode = waitForProcessExit(pid); - - synchronized (this) { - this.exitcode = exitcode; - this.hasExited = true; - this.notifyAll(); - } - - if (stdout instanceof ProcessPipeInputStream) - ((ProcessPipeInputStream) stdout).processExited(); - - if (stderr instanceof ProcessPipeInputStream) - ((ProcessPipeInputStream) stderr).processExited(); - - if (stdin instanceof ProcessPipeOutputStream) - ((ProcessPipeOutputStream) stdin).processExited(); - }); - break; - - case SOLARIS: - stdin = (fds[0] == -1) ? - ProcessBuilder.NullOutputStream.INSTANCE : - new BufferedOutputStream( - new FileOutputStream(newFileDescriptor(fds[0]))); - - stdout = (fds[1] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new BufferedInputStream( - stdout_inner_stream = - new DeferredCloseInputStream( - newFileDescriptor(fds[1]))); - - stderr = (fds[2] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new DeferredCloseInputStream(newFileDescriptor(fds[2])); - - /* - * For each subprocess forked a corresponding reaper task - * is submitted. That task is the only thread which waits - * for the subprocess to terminate and it doesn't hold any - * locks while doing so. This design allows waitFor() and - * exitStatus() to be safely executed in parallel (and they - * need no native code). - */ - processReaperExecutor.execute(() -> { - int exitcode = waitForProcessExit(pid); - - synchronized (this) { - this.exitcode = exitcode; - this.hasExited = true; - this.notifyAll(); - } - }); - break; - - case AIX: - stdin = (fds[0] == -1) ? - ProcessBuilder.NullOutputStream.INSTANCE : - new ProcessPipeOutputStream(fds[0]); - - stdout = (fds[1] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new DeferredCloseProcessPipeInputStream(fds[1]); - - stderr = (fds[2] == -1) ? - ProcessBuilder.NullInputStream.INSTANCE : - new DeferredCloseProcessPipeInputStream(fds[2]); - - processReaperExecutor.execute(() -> { - int exitcode = waitForProcessExit(pid); - - synchronized (this) { - this.exitcode = exitcode; - this.hasExited = true; - this.notifyAll(); - } - - if (stdout instanceof DeferredCloseProcessPipeInputStream) - ((DeferredCloseProcessPipeInputStream) stdout).processExited(); - - if (stderr instanceof DeferredCloseProcessPipeInputStream) - ((DeferredCloseProcessPipeInputStream) stderr).processExited(); - - if (stdin instanceof ProcessPipeOutputStream) - ((ProcessPipeOutputStream) stdin).processExited(); - }); - break; - - default: throw new AssertionError("Unsupported platform: " + platform); - } - } - - public OutputStream getOutputStream() { - return stdin; - } - - public InputStream getInputStream() { - return stdout; - } - - public InputStream getErrorStream() { - return stderr; - } - - public synchronized int waitFor() throws InterruptedException { - while (!hasExited) { - wait(); - } - return exitcode; - } - - @Override - public synchronized boolean waitFor(long timeout, TimeUnit unit) - throws InterruptedException - { - if (hasExited) return true; - if (timeout <= 0) return false; - - long remainingNanos = unit.toNanos(timeout); - long deadline = System.nanoTime() + remainingNanos; - - do { - // Round up to next millisecond - wait(TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L)); - if (hasExited) { - return true; - } - remainingNanos = deadline - System.nanoTime(); - } while (remainingNanos > 0); - return hasExited; - } - - public synchronized int exitValue() { - if (!hasExited) { - throw new IllegalThreadStateException("process hasn't exited"); - } - return exitcode; - } - - private static native void destroyProcess(int pid, boolean force); - - private void destroy(boolean force) { - switch (platform) { - case LINUX: - case BSD: - case AIX: - // There is a risk that pid will be recycled, causing us to - // kill the wrong process! So we only terminate processes - // that appear to still be running. Even with this check, - // there is an unavoidable race condition here, but the window - // is very small, and OSes try hard to not recycle pids too - // soon, so this is quite safe. - synchronized (this) { - if (!hasExited) - destroyProcess(pid, force); - } - try { stdin.close(); } catch (IOException ignored) {} - try { stdout.close(); } catch (IOException ignored) {} - try { stderr.close(); } catch (IOException ignored) {} - break; - - case SOLARIS: - // There is a risk that pid will be recycled, causing us to - // kill the wrong process! So we only terminate processes - // that appear to still be running. Even with this check, - // there is an unavoidable race condition here, but the window - // is very small, and OSes try hard to not recycle pids too - // soon, so this is quite safe. - synchronized (this) { - if (!hasExited) - destroyProcess(pid, force); - try { - stdin.close(); - if (stdout_inner_stream != null) - stdout_inner_stream.closeDeferred(stdout); - if (stderr instanceof DeferredCloseInputStream) - ((DeferredCloseInputStream) stderr) - .closeDeferred(stderr); - } catch (IOException e) { - // ignore - } - } - break; - - default: throw new AssertionError("Unsupported platform: " + platform); - } - } - - public void destroy() { - destroy(false); - } - - @Override - public Process destroyForcibly() { - destroy(true); - return this; - } - - @Override - public long getPid() { - return pid; - } - - @Override - public synchronized boolean isAlive() { - return !hasExited; - } - - private static native void init(); - - static { - init(); - } - - /** - * A buffered input stream for a subprocess pipe file descriptor - * that allows the underlying file descriptor to be reclaimed when - * the process exits, via the processExited hook. - * - * This is tricky because we do not want the user-level InputStream to be - * closed until the user invokes close(), and we need to continue to be - * able to read any buffered data lingering in the OS pipe buffer. - */ - private static class ProcessPipeInputStream extends BufferedInputStream { - private final Object closeLock = new Object(); - - ProcessPipeInputStream(int fd) { - super(new FileInputStream(newFileDescriptor(fd))); - } - private static byte[] drainInputStream(InputStream in) - throws IOException { - int n = 0; - int j; - byte[] a = null; - while ((j = in.available()) > 0) { - a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j); - n += in.read(a, n, j); - } - return (a == null || n == a.length) ? a : Arrays.copyOf(a, n); - } - - /** Called by the process reaper thread when the process exits. */ - synchronized void processExited() { - synchronized (closeLock) { - try { - InputStream in = this.in; - // this stream is closed if and only if: in == null - if (in != null) { - byte[] stragglers = drainInputStream(in); - in.close(); - this.in = (stragglers == null) ? - ProcessBuilder.NullInputStream.INSTANCE : - new ByteArrayInputStream(stragglers); - } - } catch (IOException ignored) {} - } - } - - @Override - public void close() throws IOException { - // BufferedInputStream#close() is not synchronized unlike most other - // methods. Synchronizing helps avoid race with processExited(). - synchronized (closeLock) { - super.close(); - } - } - } - - /** - * A buffered output stream for a subprocess pipe file descriptor - * that allows the underlying file descriptor to be reclaimed when - * the process exits, via the processExited hook. - */ - private static class ProcessPipeOutputStream extends BufferedOutputStream { - ProcessPipeOutputStream(int fd) { - super(new FileOutputStream(newFileDescriptor(fd))); - } - - /** Called by the process reaper thread when the process exits. */ - synchronized void processExited() { - OutputStream out = this.out; - if (out != null) { - try { - out.close(); - } catch (IOException ignored) { - // We know of no reason to get an IOException, but if - // we do, there's nothing else to do but carry on. - } - this.out = ProcessBuilder.NullOutputStream.INSTANCE; - } - } - } - - // A FileInputStream that supports the deferment of the actual close - // operation until the last pending I/O operation on the stream has - // finished. This is required on Solaris because we must close the stdin - // and stdout streams in the destroy method in order to reclaim the - // underlying file descriptors. Doing so, however, causes any thread - // currently blocked in a read on one of those streams to receive an - // IOException("Bad file number"), which is incompatible with historical - // behavior. By deferring the close we allow any pending reads to see -1 - // (EOF) as they did before. - // - private static class DeferredCloseInputStream extends FileInputStream - { - DeferredCloseInputStream(FileDescriptor fd) { - super(fd); - } - - private Object lock = new Object(); // For the following fields - private boolean closePending = false; - private int useCount = 0; - private InputStream streamToClose; - - private void raise() { - synchronized (lock) { - useCount++; - } - } - - private void lower() throws IOException { - synchronized (lock) { - useCount--; - if (useCount == 0 && closePending) { - streamToClose.close(); - } - } - } - - // stc is the actual stream to be closed; it might be this object, or - // it might be an upstream object for which this object is downstream. - // - private void closeDeferred(InputStream stc) throws IOException { - synchronized (lock) { - if (useCount == 0) { - stc.close(); - } else { - closePending = true; - streamToClose = stc; - } - } - } - - public void close() throws IOException { - synchronized (lock) { - useCount = 0; - closePending = false; - } - super.close(); - } - - public int read() throws IOException { - raise(); - try { - return super.read(); - } finally { - lower(); - } - } - - public int read(byte[] b) throws IOException { - raise(); - try { - return super.read(b); - } finally { - lower(); - } - } - - public int read(byte[] b, int off, int len) throws IOException { - raise(); - try { - return super.read(b, off, len); - } finally { - lower(); - } - } - - public long skip(long n) throws IOException { - raise(); - try { - return super.skip(n); - } finally { - lower(); - } - } - - public int available() throws IOException { - raise(); - try { - return super.available(); - } finally { - lower(); - } - } - } - - /** - * A buffered input stream for a subprocess pipe file descriptor - * that allows the underlying file descriptor to be reclaimed when - * the process exits, via the processExited hook. - * - * This is tricky because we do not want the user-level InputStream to be - * closed until the user invokes close(), and we need to continue to be - * able to read any buffered data lingering in the OS pipe buffer. - * - * On AIX this is especially tricky, because the 'close()' system call - * will block if another thread is at the same time blocked in a file - * operation (e.g. 'read()') on the same file descriptor. We therefore - * combine 'ProcessPipeInputStream' approach used on Linux and Bsd - * with the DeferredCloseInputStream approach used on Solaris. This means - * that every potentially blocking operation on the file descriptor - * increments a counter before it is executed and decrements it once it - * finishes. The 'close()' operation will only be executed if there are - * no pending operations. Otherwise it is deferred after the last pending - * operation has finished. - * - */ - private static class DeferredCloseProcessPipeInputStream - extends BufferedInputStream { - - private final Object closeLock = new Object(); - private int useCount = 0; - private boolean closePending = false; - - DeferredCloseProcessPipeInputStream(int fd) { - super(new FileInputStream(newFileDescriptor(fd))); - } - - private InputStream drainInputStream(InputStream in) - throws IOException { - int n = 0; - int j; - byte[] a = null; - synchronized (closeLock) { - if (buf == null) // asynchronous close()? - return null; // discard - j = in.available(); - } - while (j > 0) { - a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j); - synchronized (closeLock) { - if (buf == null) // asynchronous close()? - return null; // discard - n += in.read(a, n, j); - j = in.available(); - } - } - return (a == null) ? - ProcessBuilder.NullInputStream.INSTANCE : - new ByteArrayInputStream(n == a.length ? a : Arrays.copyOf(a, n)); - } - - /** Called by the process reaper thread when the process exits. */ - synchronized void processExited() { - try { - InputStream in = this.in; - if (in != null) { - InputStream stragglers = drainInputStream(in); - in.close(); - this.in = stragglers; - } - } catch (IOException ignored) { } - } - - private void raise() { - synchronized (closeLock) { - useCount++; - } - } - - private void lower() throws IOException { - synchronized (closeLock) { - useCount--; - if (useCount == 0 && closePending) { - closePending = false; - super.close(); - } - } - } - - @Override - public int read() throws IOException { - raise(); - try { - return super.read(); - } finally { - lower(); - } - } - - @Override - public int read(byte[] b) throws IOException { - raise(); - try { - return super.read(b); - } finally { - lower(); - } - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - raise(); - try { - return super.read(b, off, len); - } finally { - lower(); - } - } - - @Override - public long skip(long n) throws IOException { - raise(); - try { - return super.skip(n); - } finally { - lower(); - } - } - - @Override - public int available() throws IOException { - raise(); - try { - return super.available(); - } finally { - lower(); - } - } - - @Override - public void close() throws IOException { - // BufferedInputStream#close() is not synchronized unlike most other - // methods. Synchronizing helps avoid racing with drainInputStream(). - synchronized (closeLock) { - if (useCount == 0) { - super.close(); - } - else { - closePending = true; - } - } - } - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,724 @@ +/* + * Copyright (c) 1995, 2015, 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. + */ + +#undef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE 1 + +#include "jni.h" +#include "jvm.h" +#include "jvm_md.h" +#include "jni_util.h" +#include "io_util.h" + +/* + * Platform-specific support for java.lang.Process + */ +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> +#include <sys/types.h> +#include <ctype.h> +#include <sys/wait.h> +#include <signal.h> +#include <string.h> + +#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) +#include <spawn.h> +#endif + +#include "childproc.h" + +/* + * There are 4 possible strategies we might use to "fork": + * + * - fork(2). Very portable and reliable but subject to + * failure due to overcommit (see the documentation on + * /proc/sys/vm/overcommit_memory in Linux proc(5)). + * This is the ancient problem of spurious failure whenever a large + * process starts a small subprocess. + * + * - vfork(). Using this is scary because all relevant man pages + * contain dire warnings, e.g. Linux vfork(2). But at least it's + * documented in the glibc docs and is standardized by XPG4. + * http://www.opengroup.org/onlinepubs/000095399/functions/vfork.html + * On Linux, one might think that vfork() would be implemented using + * the clone system call with flag CLONE_VFORK, but in fact vfork is + * a separate system call (which is a good sign, suggesting that + * vfork will continue to be supported at least on Linux). + * Another good sign is that glibc implements posix_spawn using + * vfork whenever possible. Note that we cannot use posix_spawn + * ourselves because there's no reliable way to close all inherited + * file descriptors. + * + * - clone() with flags CLONE_VM but not CLONE_THREAD. clone() is + * Linux-specific, but this ought to work - at least the glibc + * sources contain code to handle different combinations of CLONE_VM + * and CLONE_THREAD. However, when this was implemented, it + * appeared to fail on 32-bit i386 (but not 64-bit x86_64) Linux with + * the simple program + * Runtime.getRuntime().exec("/bin/true").waitFor(); + * with: + * # Internal Error (os_linux_x86.cpp:683), pid=19940, tid=2934639536 + * # Error: pthread_getattr_np failed with errno = 3 (ESRCH) + * We believe this is a glibc bug, reported here: + * http://sources.redhat.com/bugzilla/show_bug.cgi?id=10311 + * but the glibc maintainers closed it as WONTFIX. + * + * - posix_spawn(). While posix_spawn() is a fairly elaborate and + * complicated system call, it can't quite do everything that the old + * fork()/exec() combination can do, so the only feasible way to do + * this, is to use posix_spawn to launch a new helper executable + * "jprochelper", which in turn execs the target (after cleaning + * up file-descriptors etc.) The end result is the same as before, + * a child process linked to the parent in the same way, but it + * avoids the problem of duplicating the parent (VM) process + * address space temporarily, before launching the target command. + * + * Based on the above analysis, we are currently using vfork() on + * Linux and spawn() on other Unix systems, but the code to use clone() + * and fork() remains. + */ + + +static void +setSIGCHLDHandler(JNIEnv *env) +{ + /* There is a subtle difference between having the signal handler + * for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process + * termination information for child processes if the signal + * handler is SIG_IGN. It must be SIG_DFL. + * + * We used to set the SIGCHLD handler only on Linux, but it's + * safest to set it unconditionally. + * + * Consider what happens if java's parent process sets the SIGCHLD + * handler to SIG_IGN. Normally signal handlers are inherited by + * children, but SIGCHLD is a controversial case. Solaris appears + * to always reset it to SIG_DFL, but this behavior may be + * non-standard-compliant, and we shouldn't rely on it. + * + * References: + * http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html + * http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html + */ + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; + if (sigaction(SIGCHLD, &sa, NULL) < 0) + JNU_ThrowInternalError(env, "Can't set SIGCHLD handler"); +} + +static void* +xmalloc(JNIEnv *env, size_t size) +{ + void *p = malloc(size); + if (p == NULL) + JNU_ThrowOutOfMemoryError(env, NULL); + return p; +} + +#define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type))) + +/** + * If PATH is not defined, the OS provides some default value. + * Unfortunately, there's no portable way to get this value. + * Fortunately, it's only needed if the child has PATH while we do not. + */ +static const char* +defaultPath(void) +{ +#ifdef __solaris__ + /* These really are the Solaris defaults! */ + return (geteuid() == 0 || getuid() == 0) ? + "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" : + "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:"; +#else + return ":/bin:/usr/bin"; /* glibc */ +#endif +} + +static const char* +effectivePath(void) +{ + const char *s = getenv("PATH"); + return (s != NULL) ? s : defaultPath(); +} + +static int +countOccurrences(const char *s, char c) +{ + int count; + for (count = 0; *s != '\0'; s++) + count += (*s == c); + return count; +} + +static const char * const * +effectivePathv(JNIEnv *env) +{ + char *p; + int i; + const char *path = effectivePath(); + int count = countOccurrences(path, ':') + 1; + size_t pathvsize = sizeof(const char *) * (count+1); + size_t pathsize = strlen(path) + 1; + const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize); + + if (pathv == NULL) + return NULL; + p = (char *) pathv + pathvsize; + memcpy(p, path, pathsize); + /* split PATH by replacing ':' with NULs; empty components => "." */ + for (i = 0; i < count; i++) { + char *q = p + strcspn(p, ":"); + pathv[i] = (p == q) ? "." : p; + *q = '\0'; + p = q + 1; + } + pathv[count] = NULL; + return pathv; +} + +JNIEXPORT void JNICALL +Java_java_lang_ProcessImpl_init(JNIEnv *env, jclass clazz) +{ + parentPathv = effectivePathv(env); + CHECK_NULL(parentPathv); + setSIGCHLDHandler(env); +} + + +#ifndef WIFEXITED +#define WIFEXITED(status) (((status)&0xFF) == 0) +#endif + +#ifndef WEXITSTATUS +#define WEXITSTATUS(status) (((status)>>8)&0xFF) +#endif + +#ifndef WIFSIGNALED +#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0) +#endif + +#ifndef WTERMSIG +#define WTERMSIG(status) ((status)&0x7F) +#endif + +/* Block until a child process exits and return its exit code. + Note, can only be called once for any given pid. */ +JNIEXPORT jint JNICALL +Java_java_lang_ProcessImpl_waitForProcessExit(JNIEnv* env, + jobject junk, + jint pid) +{ + /* We used to use waitid() on Solaris, waitpid() on Linux, but + * waitpid() is more standard, so use it on all POSIX platforms. */ + int status; + /* Wait for the child process to exit. This returns immediately if + the child has already exited. */ + while (waitpid(pid, &status, 0) < 0) { + switch (errno) { + case ECHILD: return 0; + case EINTR: break; + default: return -1; + } + } + + if (WIFEXITED(status)) { + /* + * The child exited normally; get its exit code. + */ + return WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + /* The child exited because of a signal. + * The best value to return is 0x80 + signal number, + * because that is what all Unix shells do, and because + * it allows callers to distinguish between process exit and + * process death by signal. + * Unfortunately, the historical behavior on Solaris is to return + * the signal number, and we preserve this for compatibility. */ +#ifdef __solaris__ + return WTERMSIG(status); +#else + return 0x80 + WTERMSIG(status); +#endif + } else { + /* + * Unknown exit code; pass it through. + */ + return status; + } +} + +static const char * +getBytes(JNIEnv *env, jbyteArray arr) +{ + return arr == NULL ? NULL : + (const char*) (*env)->GetByteArrayElements(env, arr, NULL); +} + +static void +releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr) +{ + if (parr != NULL) + (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT); +} + +static void +throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) +{ + static const char * const format = "error=%d, %s"; + const char *detail = defaultDetail; + char *errmsg; + jstring s; + + if (errnum != 0) { + const char *s = strerror(errnum); + if (strcmp(s, "Unknown error") != 0) + detail = s; + } + /* ASCII Decimal representation uses 2.4 times as many bits as binary. */ + errmsg = NEW(char, strlen(format) + strlen(detail) + 3 * sizeof(errnum)); + if (errmsg == NULL) + return; + + sprintf(errmsg, format, errnum, detail); + s = JNU_NewStringPlatform(env, errmsg); + if (s != NULL) { + jobject x = JNU_NewObjectByName(env, "java/io/IOException", + "(Ljava/lang/String;)V", s); + if (x != NULL) + (*env)->Throw(env, x); + } + free(errmsg); +} + +#ifdef DEBUG_PROCESS +/* Debugging process code is difficult; where to write debug output? */ +static void +debugPrint(char *format, ...) +{ + FILE *tty = fopen("/dev/tty", "w"); + va_list ap; + va_start(ap, format); + vfprintf(tty, format, ap); + va_end(ap); + fclose(tty); +} +#endif /* DEBUG_PROCESS */ + +static void +copyPipe(int from[2], int to[2]) +{ + to[0] = from[0]; + to[1] = from[1]; +} + +/* arg is an array of pointers to 0 terminated strings. array is terminated + * by a null element. + * + * *nelems and *nbytes receive the number of elements of array (incl 0) + * and total number of bytes (incl. 0) + * Note. An empty array will have one null element + * But if arg is null, then *nelems set to 0, and *nbytes to 0 + */ +static void arraysize(const char * const *arg, int *nelems, int *nbytes) +{ + int i, bytes, count; + const char * const *a = arg; + char *p; + int *q; + if (arg == 0) { + *nelems = 0; + *nbytes = 0; + return; + } + /* count the array elements and number of bytes */ + for (count=0, bytes=0; *a != 0; count++, a++) { + bytes += strlen(*a)+1; + } + *nbytes = bytes; + *nelems = count+1; +} + +/* copy the strings from arg[] into buf, starting at given offset + * return new offset to next free byte + */ +static int copystrings(char *buf, int offset, const char * const *arg) { + char *p; + const char * const *a; + int count=0; + + if (arg == 0) { + return offset; + } + for (p=buf+offset, a=arg; *a != 0; a++) { + int len = strlen(*a) +1; + memcpy(p, *a, len); + p += len; + count += len; + } + return offset+count; +} + +/** + * We are unusually paranoid; use of clone/vfork is + * especially likely to tickle gcc/glibc bugs. + */ +#ifdef __attribute_noinline__ /* See: sys/cdefs.h */ +__attribute_noinline__ +#endif + +#define START_CHILD_USE_CLONE 0 /* clone() currently disabled; see above. */ + +#ifdef START_CHILD_USE_CLONE +static pid_t +cloneChild(ChildStuff *c) { +#ifdef __linux__ +#define START_CHILD_CLONE_STACK_SIZE (64 * 1024) + /* + * See clone(2). + * Instead of worrying about which direction the stack grows, just + * allocate twice as much and start the stack in the middle. + */ + if ((c->clone_stack = malloc(2 * START_CHILD_CLONE_STACK_SIZE)) == NULL) + /* errno will be set to ENOMEM */ + return -1; + return clone(childProcess, + c->clone_stack + START_CHILD_CLONE_STACK_SIZE, + CLONE_VFORK | CLONE_VM | SIGCHLD, c); +#else +/* not available on Solaris / Mac */ + assert(0); + return -1; +#endif +} +#endif + +static pid_t +vforkChild(ChildStuff *c) { + volatile pid_t resultPid; + + /* + * We separate the call to vfork into a separate function to make + * very sure to keep stack of child from corrupting stack of parent, + * as suggested by the scary gcc warning: + * warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork' + */ + resultPid = vfork(); + + if (resultPid == 0) { + childProcess(c); + } + assert(resultPid != 0); /* childProcess never returns */ + return resultPid; +} + +static pid_t +forkChild(ChildStuff *c) { + pid_t resultPid; + + /* + * From Solaris fork(2): In Solaris 10, a call to fork() is + * identical to a call to fork1(); only the calling thread is + * replicated in the child process. This is the POSIX-specified + * behavior for fork(). + */ + resultPid = fork(); + + if (resultPid == 0) { + childProcess(c); + } + assert(resultPid != 0); /* childProcess never returns */ + return resultPid; +} + +#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) +static pid_t +spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { + pid_t resultPid; + jboolean isCopy; + int i, offset, rval, bufsize, magic; + char *buf, buf1[16]; + char *hlpargs[2]; + SpawnInfo sp; + + /* need to tell helper which fd is for receiving the childstuff + * and which fd to send response back on + */ + snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]); + /* put the fd string as argument to the helper cmd */ + hlpargs[0] = buf1; + hlpargs[1] = 0; + + /* Following items are sent down the pipe to the helper + * after it is spawned. + * All strings are null terminated. All arrays of strings + * have an empty string for termination. + * - the ChildStuff struct + * - the SpawnInfo struct + * - the argv strings array + * - the envv strings array + * - the home directory string + * - the parentPath string + * - the parentPathv array + */ + /* First calculate the sizes */ + arraysize(c->argv, &sp.nargv, &sp.argvBytes); + bufsize = sp.argvBytes; + arraysize(c->envv, &sp.nenvv, &sp.envvBytes); + bufsize += sp.envvBytes; + sp.dirlen = c->pdir == 0 ? 0 : strlen(c->pdir)+1; + bufsize += sp.dirlen; + arraysize(parentPathv, &sp.nparentPathv, &sp.parentPathvBytes); + bufsize += sp.parentPathvBytes; + /* We need to clear FD_CLOEXEC if set in the fds[]. + * Files are created FD_CLOEXEC in Java. + * Otherwise, they will be closed when the target gets exec'd */ + for (i=0; i<3; i++) { + if (c->fds[i] != -1) { + int flags = fcntl(c->fds[i], F_GETFD); + if (flags & FD_CLOEXEC) { + fcntl(c->fds[i], F_SETFD, flags & (~1)); + } + } + } + + rval = posix_spawn(&resultPid, helperpath, 0, 0, (char * const *) hlpargs, environ); + + if (rval != 0) { + return -1; + } + + /* now the lengths are known, copy the data */ + buf = NEW(char, bufsize); + if (buf == 0) { + return -1; + } + offset = copystrings(buf, 0, &c->argv[0]); + offset = copystrings(buf, offset, &c->envv[0]); + memcpy(buf+offset, c->pdir, sp.dirlen); + offset += sp.dirlen; + offset = copystrings(buf, offset, parentPathv); + assert(offset == bufsize); + + magic = magicNumber(); + + /* write the two structs and the data buffer */ + write(c->childenv[1], (char *)&magic, sizeof(magic)); // magic number first + write(c->childenv[1], (char *)c, sizeof(*c)); + write(c->childenv[1], (char *)&sp, sizeof(sp)); + write(c->childenv[1], buf, bufsize); + free(buf); + + /* In this mode an external main() in invoked which calls back into + * childProcess() in this file, rather than directly + * via the statement below */ + return resultPid; +} +#endif + +/* + * Start a child process running function childProcess. + * This function only returns in the parent. + */ +static pid_t +startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { + switch (c->mode) { + case MODE_VFORK: + return vforkChild(c); + case MODE_FORK: + return forkChild(c); +#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) + case MODE_POSIX_SPAWN: + return spawnChild(env, process, c, helperpath); +#endif + default: + return -1; + } +} + +JNIEXPORT jint JNICALL +Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, + jobject process, + jint mode, + jbyteArray helperpath, + jbyteArray prog, + jbyteArray argBlock, jint argc, + jbyteArray envBlock, jint envc, + jbyteArray dir, + jintArray std_fds, + jboolean redirectErrorStream) +{ + int errnum; + int resultPid = -1; + int in[2], out[2], err[2], fail[2], childenv[2]; + jint *fds = NULL; + const char *phelperpath = NULL; + const char *pprog = NULL; + const char *pargBlock = NULL; + const char *penvBlock = NULL; + ChildStuff *c; + + in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1; + childenv[0] = childenv[1] = -1; + + if ((c = NEW(ChildStuff, 1)) == NULL) return -1; + c->argv = NULL; + c->envv = NULL; + c->pdir = NULL; + c->clone_stack = NULL; + + /* Convert prog + argBlock into a char ** argv. + * Add one word room for expansion of argv for use by + * execve_as_traditional_shell_script. + * This word is also used when using spawn mode + */ + assert(prog != NULL && argBlock != NULL); + if ((phelperpath = getBytes(env, helperpath)) == NULL) goto Catch; + if ((pprog = getBytes(env, prog)) == NULL) goto Catch; + if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch; + if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch; + c->argv[0] = pprog; + c->argc = argc + 2; + initVectorFromBlock(c->argv+1, pargBlock, argc); + + if (envBlock != NULL) { + /* Convert envBlock into a char ** envv */ + if ((penvBlock = getBytes(env, envBlock)) == NULL) goto Catch; + if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch; + initVectorFromBlock(c->envv, penvBlock, envc); + } + + if (dir != NULL) { + if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch; + } + + assert(std_fds != NULL); + fds = (*env)->GetIntArrayElements(env, std_fds, NULL); + if (fds == NULL) goto Catch; + + if ((fds[0] == -1 && pipe(in) < 0) || + (fds[1] == -1 && pipe(out) < 0) || + (fds[2] == -1 && pipe(err) < 0) || + (pipe(childenv) < 0) || + (pipe(fail) < 0)) { + throwIOException(env, errno, "Bad file descriptor"); + goto Catch; + } + c->fds[0] = fds[0]; + c->fds[1] = fds[1]; + c->fds[2] = fds[2]; + + copyPipe(in, c->in); + copyPipe(out, c->out); + copyPipe(err, c->err); + copyPipe(fail, c->fail); + copyPipe(childenv, c->childenv); + + c->redirectErrorStream = redirectErrorStream; + c->mode = mode; + + resultPid = startChild(env, process, c, phelperpath); + assert(resultPid != 0); + + if (resultPid < 0) { + switch (c->mode) { + case MODE_VFORK: + throwIOException(env, errno, "vfork failed"); + break; + case MODE_FORK: + throwIOException(env, errno, "fork failed"); + break; + case MODE_POSIX_SPAWN: + throwIOException(env, errno, "spawn failed"); + break; + } + goto Catch; + } + close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */ + + switch (readFully(fail[0], &errnum, sizeof(errnum))) { + case 0: break; /* Exec succeeded */ + case sizeof(errnum): + waitpid(resultPid, NULL, 0); + throwIOException(env, errnum, "Exec failed"); + goto Catch; + default: + throwIOException(env, errno, "Read failed"); + goto Catch; + } + + fds[0] = (in [1] != -1) ? in [1] : -1; + fds[1] = (out[0] != -1) ? out[0] : -1; + fds[2] = (err[0] != -1) ? err[0] : -1; + + Finally: + free(c->clone_stack); + + /* Always clean up the child's side of the pipes */ + closeSafely(in [0]); + closeSafely(out[1]); + closeSafely(err[1]); + + /* Always clean up fail and childEnv descriptors */ + closeSafely(fail[0]); + closeSafely(fail[1]); + closeSafely(childenv[0]); + closeSafely(childenv[1]); + + releaseBytes(env, helperpath, phelperpath); + releaseBytes(env, prog, pprog); + releaseBytes(env, argBlock, pargBlock); + releaseBytes(env, envBlock, penvBlock); + releaseBytes(env, dir, c->pdir); + + free(c->argv); + free(c->envv); + free(c); + + if (fds != NULL) + (*env)->ReleaseIntArrayElements(env, std_fds, fds, 0); + + return resultPid; + + Catch: + /* Clean up the parent's side of the pipes in case of failure only */ + closeSafely(in [1]); in[1] = -1; + closeSafely(out[0]); out[0] = -1; + closeSafely(err[0]); err[0] = -1; + goto Finally; +} + +JNIEXPORT void JNICALL +Java_java_lang_ProcessImpl_destroyProcess(JNIEnv *env, + jobject junk, + jint pid, + jboolean force) +{ + int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM; + kill(pid, sig); +}
--- a/jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,724 +0,0 @@ -/* - * Copyright (c) 1995, 2013, 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. - */ - -#undef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE 1 - -#include "jni.h" -#include "jvm.h" -#include "jvm_md.h" -#include "jni_util.h" -#include "io_util.h" - -/* - * Platform-specific support for java.lang.Process - */ -#include <assert.h> -#include <stddef.h> -#include <stdlib.h> -#include <sys/types.h> -#include <ctype.h> -#include <sys/wait.h> -#include <signal.h> -#include <string.h> - -#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) -#include <spawn.h> -#endif - -#include "childproc.h" - -/* - * There are 4 possible strategies we might use to "fork": - * - * - fork(2). Very portable and reliable but subject to - * failure due to overcommit (see the documentation on - * /proc/sys/vm/overcommit_memory in Linux proc(5)). - * This is the ancient problem of spurious failure whenever a large - * process starts a small subprocess. - * - * - vfork(). Using this is scary because all relevant man pages - * contain dire warnings, e.g. Linux vfork(2). But at least it's - * documented in the glibc docs and is standardized by XPG4. - * http://www.opengroup.org/onlinepubs/000095399/functions/vfork.html - * On Linux, one might think that vfork() would be implemented using - * the clone system call with flag CLONE_VFORK, but in fact vfork is - * a separate system call (which is a good sign, suggesting that - * vfork will continue to be supported at least on Linux). - * Another good sign is that glibc implements posix_spawn using - * vfork whenever possible. Note that we cannot use posix_spawn - * ourselves because there's no reliable way to close all inherited - * file descriptors. - * - * - clone() with flags CLONE_VM but not CLONE_THREAD. clone() is - * Linux-specific, but this ought to work - at least the glibc - * sources contain code to handle different combinations of CLONE_VM - * and CLONE_THREAD. However, when this was implemented, it - * appeared to fail on 32-bit i386 (but not 64-bit x86_64) Linux with - * the simple program - * Runtime.getRuntime().exec("/bin/true").waitFor(); - * with: - * # Internal Error (os_linux_x86.cpp:683), pid=19940, tid=2934639536 - * # Error: pthread_getattr_np failed with errno = 3 (ESRCH) - * We believe this is a glibc bug, reported here: - * http://sources.redhat.com/bugzilla/show_bug.cgi?id=10311 - * but the glibc maintainers closed it as WONTFIX. - * - * - posix_spawn(). While posix_spawn() is a fairly elaborate and - * complicated system call, it can't quite do everything that the old - * fork()/exec() combination can do, so the only feasible way to do - * this, is to use posix_spawn to launch a new helper executable - * "jprochelper", which in turn execs the target (after cleaning - * up file-descriptors etc.) The end result is the same as before, - * a child process linked to the parent in the same way, but it - * avoids the problem of duplicating the parent (VM) process - * address space temporarily, before launching the target command. - * - * Based on the above analysis, we are currently using vfork() on - * Linux and spawn() on other Unix systems, but the code to use clone() - * and fork() remains. - */ - - -static void -setSIGCHLDHandler(JNIEnv *env) -{ - /* There is a subtle difference between having the signal handler - * for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process - * termination information for child processes if the signal - * handler is SIG_IGN. It must be SIG_DFL. - * - * We used to set the SIGCHLD handler only on Linux, but it's - * safest to set it unconditionally. - * - * Consider what happens if java's parent process sets the SIGCHLD - * handler to SIG_IGN. Normally signal handlers are inherited by - * children, but SIGCHLD is a controversial case. Solaris appears - * to always reset it to SIG_DFL, but this behavior may be - * non-standard-compliant, and we shouldn't rely on it. - * - * References: - * http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html - * http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html - */ - struct sigaction sa; - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; - if (sigaction(SIGCHLD, &sa, NULL) < 0) - JNU_ThrowInternalError(env, "Can't set SIGCHLD handler"); -} - -static void* -xmalloc(JNIEnv *env, size_t size) -{ - void *p = malloc(size); - if (p == NULL) - JNU_ThrowOutOfMemoryError(env, NULL); - return p; -} - -#define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type))) - -/** - * If PATH is not defined, the OS provides some default value. - * Unfortunately, there's no portable way to get this value. - * Fortunately, it's only needed if the child has PATH while we do not. - */ -static const char* -defaultPath(void) -{ -#ifdef __solaris__ - /* These really are the Solaris defaults! */ - return (geteuid() == 0 || getuid() == 0) ? - "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" : - "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:"; -#else - return ":/bin:/usr/bin"; /* glibc */ -#endif -} - -static const char* -effectivePath(void) -{ - const char *s = getenv("PATH"); - return (s != NULL) ? s : defaultPath(); -} - -static int -countOccurrences(const char *s, char c) -{ - int count; - for (count = 0; *s != '\0'; s++) - count += (*s == c); - return count; -} - -static const char * const * -effectivePathv(JNIEnv *env) -{ - char *p; - int i; - const char *path = effectivePath(); - int count = countOccurrences(path, ':') + 1; - size_t pathvsize = sizeof(const char *) * (count+1); - size_t pathsize = strlen(path) + 1; - const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize); - - if (pathv == NULL) - return NULL; - p = (char *) pathv + pathvsize; - memcpy(p, path, pathsize); - /* split PATH by replacing ':' with NULs; empty components => "." */ - for (i = 0; i < count; i++) { - char *q = p + strcspn(p, ":"); - pathv[i] = (p == q) ? "." : p; - *q = '\0'; - p = q + 1; - } - pathv[count] = NULL; - return pathv; -} - -JNIEXPORT void JNICALL -Java_java_lang_UNIXProcess_init(JNIEnv *env, jclass clazz) -{ - parentPathv = effectivePathv(env); - CHECK_NULL(parentPathv); - setSIGCHLDHandler(env); -} - - -#ifndef WIFEXITED -#define WIFEXITED(status) (((status)&0xFF) == 0) -#endif - -#ifndef WEXITSTATUS -#define WEXITSTATUS(status) (((status)>>8)&0xFF) -#endif - -#ifndef WIFSIGNALED -#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0) -#endif - -#ifndef WTERMSIG -#define WTERMSIG(status) ((status)&0x7F) -#endif - -/* Block until a child process exits and return its exit code. - Note, can only be called once for any given pid. */ -JNIEXPORT jint JNICALL -Java_java_lang_UNIXProcess_waitForProcessExit(JNIEnv* env, - jobject junk, - jint pid) -{ - /* We used to use waitid() on Solaris, waitpid() on Linux, but - * waitpid() is more standard, so use it on all POSIX platforms. */ - int status; - /* Wait for the child process to exit. This returns immediately if - the child has already exited. */ - while (waitpid(pid, &status, 0) < 0) { - switch (errno) { - case ECHILD: return 0; - case EINTR: break; - default: return -1; - } - } - - if (WIFEXITED(status)) { - /* - * The child exited normally; get its exit code. - */ - return WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) { - /* The child exited because of a signal. - * The best value to return is 0x80 + signal number, - * because that is what all Unix shells do, and because - * it allows callers to distinguish between process exit and - * process death by signal. - * Unfortunately, the historical behavior on Solaris is to return - * the signal number, and we preserve this for compatibility. */ -#ifdef __solaris__ - return WTERMSIG(status); -#else - return 0x80 + WTERMSIG(status); -#endif - } else { - /* - * Unknown exit code; pass it through. - */ - return status; - } -} - -static const char * -getBytes(JNIEnv *env, jbyteArray arr) -{ - return arr == NULL ? NULL : - (const char*) (*env)->GetByteArrayElements(env, arr, NULL); -} - -static void -releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr) -{ - if (parr != NULL) - (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT); -} - -static void -throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) -{ - static const char * const format = "error=%d, %s"; - const char *detail = defaultDetail; - char *errmsg; - jstring s; - - if (errnum != 0) { - const char *s = strerror(errnum); - if (strcmp(s, "Unknown error") != 0) - detail = s; - } - /* ASCII Decimal representation uses 2.4 times as many bits as binary. */ - errmsg = NEW(char, strlen(format) + strlen(detail) + 3 * sizeof(errnum)); - if (errmsg == NULL) - return; - - sprintf(errmsg, format, errnum, detail); - s = JNU_NewStringPlatform(env, errmsg); - if (s != NULL) { - jobject x = JNU_NewObjectByName(env, "java/io/IOException", - "(Ljava/lang/String;)V", s); - if (x != NULL) - (*env)->Throw(env, x); - } - free(errmsg); -} - -#ifdef DEBUG_PROCESS -/* Debugging process code is difficult; where to write debug output? */ -static void -debugPrint(char *format, ...) -{ - FILE *tty = fopen("/dev/tty", "w"); - va_list ap; - va_start(ap, format); - vfprintf(tty, format, ap); - va_end(ap); - fclose(tty); -} -#endif /* DEBUG_PROCESS */ - -static void -copyPipe(int from[2], int to[2]) -{ - to[0] = from[0]; - to[1] = from[1]; -} - -/* arg is an array of pointers to 0 terminated strings. array is terminated - * by a null element. - * - * *nelems and *nbytes receive the number of elements of array (incl 0) - * and total number of bytes (incl. 0) - * Note. An empty array will have one null element - * But if arg is null, then *nelems set to 0, and *nbytes to 0 - */ -static void arraysize(const char * const *arg, int *nelems, int *nbytes) -{ - int i, bytes, count; - const char * const *a = arg; - char *p; - int *q; - if (arg == 0) { - *nelems = 0; - *nbytes = 0; - return; - } - /* count the array elements and number of bytes */ - for (count=0, bytes=0; *a != 0; count++, a++) { - bytes += strlen(*a)+1; - } - *nbytes = bytes; - *nelems = count+1; -} - -/* copy the strings from arg[] into buf, starting at given offset - * return new offset to next free byte - */ -static int copystrings(char *buf, int offset, const char * const *arg) { - char *p; - const char * const *a; - int count=0; - - if (arg == 0) { - return offset; - } - for (p=buf+offset, a=arg; *a != 0; a++) { - int len = strlen(*a) +1; - memcpy(p, *a, len); - p += len; - count += len; - } - return offset+count; -} - -/** - * We are unusually paranoid; use of clone/vfork is - * especially likely to tickle gcc/glibc bugs. - */ -#ifdef __attribute_noinline__ /* See: sys/cdefs.h */ -__attribute_noinline__ -#endif - -#define START_CHILD_USE_CLONE 0 /* clone() currently disabled; see above. */ - -#ifdef START_CHILD_USE_CLONE -static pid_t -cloneChild(ChildStuff *c) { -#ifdef __linux__ -#define START_CHILD_CLONE_STACK_SIZE (64 * 1024) - /* - * See clone(2). - * Instead of worrying about which direction the stack grows, just - * allocate twice as much and start the stack in the middle. - */ - if ((c->clone_stack = malloc(2 * START_CHILD_CLONE_STACK_SIZE)) == NULL) - /* errno will be set to ENOMEM */ - return -1; - return clone(childProcess, - c->clone_stack + START_CHILD_CLONE_STACK_SIZE, - CLONE_VFORK | CLONE_VM | SIGCHLD, c); -#else -/* not available on Solaris / Mac */ - assert(0); - return -1; -#endif -} -#endif - -static pid_t -vforkChild(ChildStuff *c) { - volatile pid_t resultPid; - - /* - * We separate the call to vfork into a separate function to make - * very sure to keep stack of child from corrupting stack of parent, - * as suggested by the scary gcc warning: - * warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork' - */ - resultPid = vfork(); - - if (resultPid == 0) { - childProcess(c); - } - assert(resultPid != 0); /* childProcess never returns */ - return resultPid; -} - -static pid_t -forkChild(ChildStuff *c) { - pid_t resultPid; - - /* - * From Solaris fork(2): In Solaris 10, a call to fork() is - * identical to a call to fork1(); only the calling thread is - * replicated in the child process. This is the POSIX-specified - * behavior for fork(). - */ - resultPid = fork(); - - if (resultPid == 0) { - childProcess(c); - } - assert(resultPid != 0); /* childProcess never returns */ - return resultPid; -} - -#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) -static pid_t -spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { - pid_t resultPid; - jboolean isCopy; - int i, offset, rval, bufsize, magic; - char *buf, buf1[16]; - char *hlpargs[2]; - SpawnInfo sp; - - /* need to tell helper which fd is for receiving the childstuff - * and which fd to send response back on - */ - snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]); - /* put the fd string as argument to the helper cmd */ - hlpargs[0] = buf1; - hlpargs[1] = 0; - - /* Following items are sent down the pipe to the helper - * after it is spawned. - * All strings are null terminated. All arrays of strings - * have an empty string for termination. - * - the ChildStuff struct - * - the SpawnInfo struct - * - the argv strings array - * - the envv strings array - * - the home directory string - * - the parentPath string - * - the parentPathv array - */ - /* First calculate the sizes */ - arraysize(c->argv, &sp.nargv, &sp.argvBytes); - bufsize = sp.argvBytes; - arraysize(c->envv, &sp.nenvv, &sp.envvBytes); - bufsize += sp.envvBytes; - sp.dirlen = c->pdir == 0 ? 0 : strlen(c->pdir)+1; - bufsize += sp.dirlen; - arraysize(parentPathv, &sp.nparentPathv, &sp.parentPathvBytes); - bufsize += sp.parentPathvBytes; - /* We need to clear FD_CLOEXEC if set in the fds[]. - * Files are created FD_CLOEXEC in Java. - * Otherwise, they will be closed when the target gets exec'd */ - for (i=0; i<3; i++) { - if (c->fds[i] != -1) { - int flags = fcntl(c->fds[i], F_GETFD); - if (flags & FD_CLOEXEC) { - fcntl(c->fds[i], F_SETFD, flags & (~1)); - } - } - } - - rval = posix_spawn(&resultPid, helperpath, 0, 0, (char * const *) hlpargs, environ); - - if (rval != 0) { - return -1; - } - - /* now the lengths are known, copy the data */ - buf = NEW(char, bufsize); - if (buf == 0) { - return -1; - } - offset = copystrings(buf, 0, &c->argv[0]); - offset = copystrings(buf, offset, &c->envv[0]); - memcpy(buf+offset, c->pdir, sp.dirlen); - offset += sp.dirlen; - offset = copystrings(buf, offset, parentPathv); - assert(offset == bufsize); - - magic = magicNumber(); - - /* write the two structs and the data buffer */ - write(c->childenv[1], (char *)&magic, sizeof(magic)); // magic number first - write(c->childenv[1], (char *)c, sizeof(*c)); - write(c->childenv[1], (char *)&sp, sizeof(sp)); - write(c->childenv[1], buf, bufsize); - free(buf); - - /* In this mode an external main() in invoked which calls back into - * childProcess() in this file, rather than directly - * via the statement below */ - return resultPid; -} -#endif - -/* - * Start a child process running function childProcess. - * This function only returns in the parent. - */ -static pid_t -startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { - switch (c->mode) { - case MODE_VFORK: - return vforkChild(c); - case MODE_FORK: - return forkChild(c); -#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) - case MODE_POSIX_SPAWN: - return spawnChild(env, process, c, helperpath); -#endif - default: - return -1; - } -} - -JNIEXPORT jint JNICALL -Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env, - jobject process, - jint mode, - jbyteArray helperpath, - jbyteArray prog, - jbyteArray argBlock, jint argc, - jbyteArray envBlock, jint envc, - jbyteArray dir, - jintArray std_fds, - jboolean redirectErrorStream) -{ - int errnum; - int resultPid = -1; - int in[2], out[2], err[2], fail[2], childenv[2]; - jint *fds = NULL; - const char *phelperpath = NULL; - const char *pprog = NULL; - const char *pargBlock = NULL; - const char *penvBlock = NULL; - ChildStuff *c; - - in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1; - childenv[0] = childenv[1] = -1; - - if ((c = NEW(ChildStuff, 1)) == NULL) return -1; - c->argv = NULL; - c->envv = NULL; - c->pdir = NULL; - c->clone_stack = NULL; - - /* Convert prog + argBlock into a char ** argv. - * Add one word room for expansion of argv for use by - * execve_as_traditional_shell_script. - * This word is also used when using spawn mode - */ - assert(prog != NULL && argBlock != NULL); - if ((phelperpath = getBytes(env, helperpath)) == NULL) goto Catch; - if ((pprog = getBytes(env, prog)) == NULL) goto Catch; - if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch; - if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch; - c->argv[0] = pprog; - c->argc = argc + 2; - initVectorFromBlock(c->argv+1, pargBlock, argc); - - if (envBlock != NULL) { - /* Convert envBlock into a char ** envv */ - if ((penvBlock = getBytes(env, envBlock)) == NULL) goto Catch; - if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch; - initVectorFromBlock(c->envv, penvBlock, envc); - } - - if (dir != NULL) { - if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch; - } - - assert(std_fds != NULL); - fds = (*env)->GetIntArrayElements(env, std_fds, NULL); - if (fds == NULL) goto Catch; - - if ((fds[0] == -1 && pipe(in) < 0) || - (fds[1] == -1 && pipe(out) < 0) || - (fds[2] == -1 && pipe(err) < 0) || - (pipe(childenv) < 0) || - (pipe(fail) < 0)) { - throwIOException(env, errno, "Bad file descriptor"); - goto Catch; - } - c->fds[0] = fds[0]; - c->fds[1] = fds[1]; - c->fds[2] = fds[2]; - - copyPipe(in, c->in); - copyPipe(out, c->out); - copyPipe(err, c->err); - copyPipe(fail, c->fail); - copyPipe(childenv, c->childenv); - - c->redirectErrorStream = redirectErrorStream; - c->mode = mode; - - resultPid = startChild(env, process, c, phelperpath); - assert(resultPid != 0); - - if (resultPid < 0) { - switch (c->mode) { - case MODE_VFORK: - throwIOException(env, errno, "vfork failed"); - break; - case MODE_FORK: - throwIOException(env, errno, "fork failed"); - break; - case MODE_POSIX_SPAWN: - throwIOException(env, errno, "spawn failed"); - break; - } - goto Catch; - } - close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */ - - switch (readFully(fail[0], &errnum, sizeof(errnum))) { - case 0: break; /* Exec succeeded */ - case sizeof(errnum): - waitpid(resultPid, NULL, 0); - throwIOException(env, errnum, "Exec failed"); - goto Catch; - default: - throwIOException(env, errno, "Read failed"); - goto Catch; - } - - fds[0] = (in [1] != -1) ? in [1] : -1; - fds[1] = (out[0] != -1) ? out[0] : -1; - fds[2] = (err[0] != -1) ? err[0] : -1; - - Finally: - free(c->clone_stack); - - /* Always clean up the child's side of the pipes */ - closeSafely(in [0]); - closeSafely(out[1]); - closeSafely(err[1]); - - /* Always clean up fail and childEnv descriptors */ - closeSafely(fail[0]); - closeSafely(fail[1]); - closeSafely(childenv[0]); - closeSafely(childenv[1]); - - releaseBytes(env, helperpath, phelperpath); - releaseBytes(env, prog, pprog); - releaseBytes(env, argBlock, pargBlock); - releaseBytes(env, envBlock, penvBlock); - releaseBytes(env, dir, c->pdir); - - free(c->argv); - free(c->envv); - free(c); - - if (fds != NULL) - (*env)->ReleaseIntArrayElements(env, std_fds, fds, 0); - - return resultPid; - - Catch: - /* Clean up the parent's side of the pipes in case of failure only */ - closeSafely(in [1]); in[1] = -1; - closeSafely(out[0]); out[0] = -1; - closeSafely(err[0]); err[0] = -1; - goto Finally; -} - -JNIEXPORT void JNICALL -Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env, - jobject junk, - jint pid, - jboolean force) -{ - int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM; - kill(pid, sig); -}
--- a/jdk/src/java.base/unix/native/libjava/childproc.h Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/unix/native/libjava/childproc.h Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -79,7 +79,7 @@ } while((_result == -1) && (errno == EINTR)); \ } while(0) -/* These numbers must be the same as the Enum in UNIXProcess.java +/* These numbers must be the same as the Enum in ProcessImpl.java * Must be a better way of doing this. */ #define MODE_FORK 1
--- a/jdk/src/java.base/unix/native/libjava/java_props_macosx.c Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,349 +0,0 @@ -/* - * Copyright (c) 1998, 2013, 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. - */ - -#include <dlfcn.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <Security/AuthSession.h> -#include <CoreFoundation/CoreFoundation.h> -#include <SystemConfiguration/SystemConfiguration.h> -#include <Foundation/Foundation.h> - -#include "java_props_macosx.h" - - -// need dlopen/dlsym trick to avoid pulling in JavaRuntimeSupport before libjava.dylib is loaded -static void *getJRSFramework() { - static void *jrsFwk = NULL; - if (jrsFwk == NULL) { - jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL); - } - return jrsFwk; -} - -char *getPosixLocale(int cat) { - char *lc = setlocale(cat, NULL); - if ((lc == NULL) || (strcmp(lc, "C") == 0)) { - lc = getenv("LANG"); - } - if (lc == NULL) return NULL; - return strdup(lc); -} - -#define LOCALEIDLENGTH 128 -char *getMacOSXLocale(int cat) { - switch (cat) { - case LC_MESSAGES: - { - void *jrsFwk = getJRSFramework(); - if (jrsFwk == NULL) return NULL; - - char *(*JRSCopyPrimaryLanguage)() = dlsym(jrsFwk, "JRSCopyPrimaryLanguage"); - char *primaryLanguage = JRSCopyPrimaryLanguage ? JRSCopyPrimaryLanguage() : NULL; - if (primaryLanguage == NULL) return NULL; - - char *(*JRSCopyCanonicalLanguageForPrimaryLanguage)(char *) = dlsym(jrsFwk, "JRSCopyCanonicalLanguageForPrimaryLanguage"); - char *canonicalLanguage = JRSCopyCanonicalLanguageForPrimaryLanguage ? JRSCopyCanonicalLanguageForPrimaryLanguage(primaryLanguage) : NULL; - free (primaryLanguage); - - return canonicalLanguage; - } - break; - default: - { - char localeString[LOCALEIDLENGTH]; - if (CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()), - localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding())) { - return strdup(localeString); - } - } - break; - } - - return NULL; -} - -char *setupMacOSXLocale(int cat) { - char * ret = getMacOSXLocale(cat); - - if (cat == LC_MESSAGES && ret != NULL) { - void *jrsFwk = getJRSFramework(); - if (jrsFwk != NULL) { - void (*JRSSetDefaultLocalization)(char *) = dlsym(jrsFwk, "JRSSetDefaultLocalization"); - if (JRSSetDefaultLocalization) JRSSetDefaultLocalization(ret); - } - } - - if (ret == NULL) { - return getPosixLocale(cat); - } else { - return ret; - } -} - -int isInAquaSession() { - // environment variable to bypass the aqua session check - char *ev = getenv("AWT_FORCE_HEADFUL"); - if (ev && (strncasecmp(ev, "true", 4) == 0)) { - // if "true" then tell the caller we're in an Aqua session without actually checking - return 1; - } - // Is the WindowServer available? - SecuritySessionId session_id; - SessionAttributeBits session_info; - OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info); - if (status == noErr) { - if (session_info & sessionHasGraphicAccess) { - return 1; - } - } - return 0; -} - -void setOSNameAndVersion(java_props_t *sprops) { - /* Don't rely on JRSCopyOSName because there's no guarantee the value will - * remain the same, or even if the JRS functions will continue to be part of - * Mac OS X. So hardcode os_name, and fill in os_version if we can. - */ - sprops->os_name = strdup("Mac OS X"); - - void *jrsFwk = getJRSFramework(); - if (jrsFwk != NULL) { - char *(*copyOSVersion)() = dlsym(jrsFwk, "JRSCopyOSVersion"); - if (copyOSVersion != NULL) { - sprops->os_version = copyOSVersion(); - return; - } - } - sprops->os_version = strdup("Unknown"); -} - - -static Boolean getProxyInfoForProtocol(CFDictionaryRef inDict, CFStringRef inEnabledKey, CFStringRef inHostKey, CFStringRef inPortKey, CFStringRef *outProxyHost, int *ioProxyPort) { - /* See if the proxy is enabled. */ - CFNumberRef cf_enabled = CFDictionaryGetValue(inDict, inEnabledKey); - if (cf_enabled == NULL) { - return false; - } - - int isEnabled = false; - if (!CFNumberGetValue(cf_enabled, kCFNumberIntType, &isEnabled)) { - return isEnabled; - } - - if (!isEnabled) return false; - *outProxyHost = CFDictionaryGetValue(inDict, inHostKey); - - // If cf_host is null, that means the checkbox is set, - // but no host was entered. We'll treat that as NOT ENABLED. - // If cf_port is null or cf_port isn't a number, that means - // no port number was entered. Treat this as ENABLED with the - // protocol's default port. - if (*outProxyHost == NULL) { - return false; - } - - if (CFStringGetLength(*outProxyHost) == 0) { - return false; - } - - int newPort = 0; - CFNumberRef cf_port = NULL; - if ((cf_port = CFDictionaryGetValue(inDict, inPortKey)) != NULL && - CFNumberGetValue(cf_port, kCFNumberIntType, &newPort) && - newPort > 0) { - *ioProxyPort = newPort; - } else { - // bad port or no port - leave *ioProxyPort unchanged - } - - return true; -} - -static char *createUTF8CString(const CFStringRef theString) { - if (theString == NULL) return NULL; - - const CFIndex stringLength = CFStringGetLength(theString); - const CFIndex bufSize = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 1; - char *returnVal = (char *)malloc(bufSize); - - if (CFStringGetCString(theString, returnVal, bufSize, kCFStringEncodingUTF8)) { - return returnVal; - } - - free(returnVal); - return NULL; -} - -// Return TRUE if str is a syntactically valid IP address. -// Using inet_pton() instead of inet_aton() for IPv6 support. -// len is only a hint; cstr must still be nul-terminated -static int looksLikeIPAddress(char *cstr, size_t len) { - if (len == 0 || (len == 1 && cstr[0] == '.')) return FALSE; - - char dst[16]; // big enough for INET6 - return (1 == inet_pton(AF_INET, cstr, dst) || - 1 == inet_pton(AF_INET6, cstr, dst)); -} - - - -// Convert Mac OS X proxy exception entry to Java syntax. -// See Radar #3441134 for details. -// Returns NULL if this exception should be ignored by Java. -// May generate a string with multiple exceptions separated by '|'. -static char * createConvertedException(CFStringRef cf_original) { - // This is done with char* instead of CFString because inet_pton() - // needs a C string. - char *c_exception = createUTF8CString(cf_original); - if (!c_exception) return NULL; - - int c_len = strlen(c_exception); - - // 1. sanitize exception prefix - if (c_len >= 1 && 0 == strncmp(c_exception, ".", 1)) { - memmove(c_exception, c_exception+1, c_len); - c_len -= 1; - } else if (c_len >= 2 && 0 == strncmp(c_exception, "*.", 2)) { - memmove(c_exception, c_exception+2, c_len-1); - c_len -= 2; - } - - // 2. pre-reject other exception wildcards - if (strchr(c_exception, '*')) { - free(c_exception); - return NULL; - } - - // 3. no IP wildcarding - if (looksLikeIPAddress(c_exception, c_len)) { - return c_exception; - } - - // 4. allow domain suffixes - // c_exception is now "str\0" - change to "str|*.str\0" - c_exception = reallocf(c_exception, c_len+3+c_len+1); - if (!c_exception) return NULL; - - strncpy(c_exception+c_len, "|*.", 3); - strncpy(c_exception+c_len+3, c_exception, c_len); - c_exception[c_len+3+c_len] = '\0'; - return c_exception; -} - -/* - * Method for fetching the user.home path and storing it in the property list. - * For signed .apps running in the Mac App Sandbox, user.home is set to the - * app's sandbox container. - */ -void setUserHome(java_props_t *sprops) { - if (sprops == NULL) { return; } - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - sprops->user_home = createUTF8CString((CFStringRef)NSHomeDirectory()); - [pool drain]; -} - -/* - * Method for fetching proxy info and storing it in the property list. - */ -void setProxyProperties(java_props_t *sProps) { - if (sProps == NULL) return; - - char buf[16]; /* Used for %d of an int - 16 is plenty */ - CFStringRef - cf_httpHost = NULL, - cf_httpsHost = NULL, - cf_ftpHost = NULL, - cf_socksHost = NULL, - cf_gopherHost = NULL; - int - httpPort = 80, // Default proxy port values - httpsPort = 443, - ftpPort = 21, - socksPort = 1080, - gopherPort = 70; - - CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL); - if (dict == NULL) return; - - /* Read the proxy exceptions list */ - CFArrayRef cf_list = CFDictionaryGetValue(dict, kSCPropNetProxiesExceptionsList); - - CFMutableStringRef cf_exceptionList = NULL; - if (cf_list != NULL) { - CFIndex len = CFArrayGetCount(cf_list), idx; - - cf_exceptionList = CFStringCreateMutable(NULL, 0); - for (idx = (CFIndex)0; idx < len; idx++) { - CFStringRef cf_ehost; - if ((cf_ehost = CFArrayGetValueAtIndex(cf_list, idx))) { - /* Convert this exception from Mac OS X syntax to Java syntax. - See Radar #3441134 for details. This may generate a string - with multiple Java exceptions separated by '|'. */ - char *c_exception = createConvertedException(cf_ehost); - if (c_exception) { - /* Append the host to the list of exclusions. */ - if (CFStringGetLength(cf_exceptionList) > 0) { - CFStringAppendCString(cf_exceptionList, "|", kCFStringEncodingMacRoman); - } - CFStringAppendCString(cf_exceptionList, c_exception, kCFStringEncodingMacRoman); - free(c_exception); - } - } - } - } - - if (cf_exceptionList != NULL) { - if (CFStringGetLength(cf_exceptionList) > 0) { - sProps->exceptionList = createUTF8CString(cf_exceptionList); - } - CFRelease(cf_exceptionList); - } - -#define CHECK_PROXY(protocol, PROTOCOL) \ - sProps->protocol##ProxyEnabled = \ - getProxyInfoForProtocol(dict, kSCPropNetProxies##PROTOCOL##Enable, \ - kSCPropNetProxies##PROTOCOL##Proxy, \ - kSCPropNetProxies##PROTOCOL##Port, \ - &cf_##protocol##Host, &protocol##Port); \ - if (sProps->protocol##ProxyEnabled) { \ - sProps->protocol##Host = createUTF8CString(cf_##protocol##Host); \ - snprintf(buf, sizeof(buf), "%d", protocol##Port); \ - sProps->protocol##Port = malloc(strlen(buf) + 1); \ - strcpy(sProps->protocol##Port, buf); \ - } - - CHECK_PROXY(http, HTTP); - CHECK_PROXY(https, HTTPS); - CHECK_PROXY(ftp, FTP); - CHECK_PROXY(socks, SOCKS); - CHECK_PROXY(gopher, Gopher); - -#undef CHECK_PROXY - - CFRelease(dict); -}
--- a/jdk/src/java.base/unix/native/libjava/java_props_macosx.h Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 1998, 2013, 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. - */ - -#include "java_props.h" - -char *setupMacOSXLocale(int cat); -void setOSNameAndVersion(java_props_t *sprops); -void setUserHome(java_props_t *sprops); -void setProxyProperties(java_props_t *sProps); -int isInAquaSession();
--- a/jdk/src/java.base/unix/native/libnet/bsd_close.c Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,421 +0,0 @@ -/* - * Copyright (c) 2001, 2012, 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <sys/param.h> -#include <signal.h> -#include <pthread.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/select.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <sys/poll.h> - -/* - * Stack allocated by thread when doing blocking operation - */ -typedef struct threadEntry { - pthread_t thr; /* this thread */ - struct threadEntry *next; /* next thread */ - int intr; /* interrupted */ -} threadEntry_t; - -/* - * Heap allocated during initialized - one entry per fd - */ -typedef struct { - pthread_mutex_t lock; /* fd lock */ - threadEntry_t *threads; /* threads blocked on fd */ -} fdEntry_t; - -/* - * Signal to unblock thread - */ -static int sigWakeup = SIGIO; - -/* - * The fd table and the number of file descriptors - */ -static fdEntry_t *fdTable; -static int fdCount; - -/* - * This limit applies if getlimit() returns unlimited. - * Unfortunately, this means if someone wants a higher limit - * then they have to set an explicit limit, higher than this, - * which is probably counter-intuitive. - */ -#define MAX_FD_COUNT 4096 - -/* - * Null signal handler - */ -static void sig_wakeup(int sig) { -} - -/* - * Initialization routine (executed when library is loaded) - * Allocate fd tables and sets up signal handler. - */ -static void __attribute((constructor)) init() { - struct rlimit nbr_files; - sigset_t sigset; - struct sigaction sa; - int i; - - /* - * Allocate table based on the maximum number of - * file descriptors. - */ - getrlimit(RLIMIT_NOFILE, &nbr_files); - if (nbr_files.rlim_max == RLIM_INFINITY) { - fdCount = MAX_FD_COUNT; - } else { - fdCount = nbr_files.rlim_max; - } - fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); - if (fdTable == NULL) { - fprintf(stderr, "library initialization failed - " - "unable to allocate file descriptor table - out of memory"); - abort(); - } - for (i=0; i<fdCount; i++) { - pthread_mutex_init(&fdTable[i].lock, NULL); - } - - /* - * Setup the signal handler - */ - sa.sa_handler = sig_wakeup; - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - sigaction(sigWakeup, &sa, NULL); - - sigemptyset(&sigset); - sigaddset(&sigset, sigWakeup); - sigprocmask(SIG_UNBLOCK, &sigset, NULL); -} - -/* - * Return the fd table for this fd or NULL is fd out - * of range. - */ -static inline fdEntry_t *getFdEntry(int fd) -{ - if (fd < 0 || fd >= fdCount) { - return NULL; - } - return &fdTable[fd]; -} - -/* - * Start a blocking operation :- - * Insert thread onto thread list for the fd. - */ -static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) -{ - self->thr = pthread_self(); - self->intr = 0; - - pthread_mutex_lock(&(fdEntry->lock)); - { - self->next = fdEntry->threads; - fdEntry->threads = self; - } - pthread_mutex_unlock(&(fdEntry->lock)); -} - -/* - * End a blocking operation :- - * Remove thread from thread list for the fd - * If fd has been interrupted then set errno to EBADF - */ -static inline void endOp - (fdEntry_t *fdEntry, threadEntry_t *self) -{ - int orig_errno = errno; - pthread_mutex_lock(&(fdEntry->lock)); - { - threadEntry_t *curr, *prev=NULL; - curr = fdEntry->threads; - while (curr != NULL) { - if (curr == self) { - if (curr->intr) { - orig_errno = EBADF; - } - if (prev == NULL) { - fdEntry->threads = curr->next; - } else { - prev->next = curr->next; - } - break; - } - prev = curr; - curr = curr->next; - } - } - pthread_mutex_unlock(&(fdEntry->lock)); - errno = orig_errno; -} - -/* - * Close or dup2 a file descriptor ensuring that all threads blocked on - * the file descriptor are notified via a wakeup signal. - * - * fd1 < 0 => close(fd2) - * fd1 >= 0 => dup2(fd1, fd2) - * - * Returns -1 with errno set if operation fails. - */ -static int closefd(int fd1, int fd2) { - int rv, orig_errno; - fdEntry_t *fdEntry = getFdEntry(fd2); - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* - * Lock the fd to hold-off additional I/O on this fd. - */ - pthread_mutex_lock(&(fdEntry->lock)); - - { - /* - * Send a wakeup signal to all threads blocked on this - * file descriptor. - */ - threadEntry_t *curr = fdEntry->threads; - while (curr != NULL) { - curr->intr = 1; - pthread_kill( curr->thr, sigWakeup ); - curr = curr->next; - } - - /* - * And close/dup the file descriptor - * (restart if interrupted by signal) - */ - do { - if (fd1 < 0) { - rv = close(fd2); - } else { - rv = dup2(fd1, fd2); - } - } while (rv == -1 && errno == EINTR); - - } - - /* - * Unlock without destroying errno - */ - orig_errno = errno; - pthread_mutex_unlock(&(fdEntry->lock)); - errno = orig_errno; - - return rv; -} - -/* - * Wrapper for dup2 - same semantics as dup2 system call except - * that any threads blocked in an I/O system call on fd2 will be - * preempted and return -1/EBADF; - */ -int NET_Dup2(int fd, int fd2) { - if (fd < 0) { - errno = EBADF; - return -1; - } - return closefd(fd, fd2); -} - -/* - * Wrapper for close - same semantics as close system call - * except that any threads blocked in an I/O on fd will be - * preempted and the I/O system call will return -1/EBADF. - */ -int NET_SocketClose(int fd) { - return closefd(-1, fd); -} - -/************** Basic I/O operations here ***************/ - -/* - * Macro to perform a blocking IO operation. Restarts - * automatically if interrupted by signal (other than - * our wakeup signal) - */ -#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ - int ret; \ - threadEntry_t self; \ - fdEntry_t *fdEntry = getFdEntry(FD); \ - if (fdEntry == NULL) { \ - errno = EBADF; \ - return -1; \ - } \ - do { \ - startOp(fdEntry, &self); \ - ret = FUNC; \ - endOp(fdEntry, &self); \ - } while (ret == -1 && errno == EINTR); \ - return ret; \ -} - -int NET_Read(int s, void* buf, size_t len) { - BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); -} - -int NET_ReadV(int s, const struct iovec * vector, int count) { - BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); -} - -int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, - struct sockaddr *from, socklen_t *fromlen) { - BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) ); -} - -int NET_Send(int s, void *msg, int len, unsigned int flags) { - BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); -} - -int NET_WriteV(int s, const struct iovec * vector, int count) { - BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); -} - -int NET_SendTo(int s, const void *msg, int len, unsigned int - flags, const struct sockaddr *to, int tolen) { - BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); -} - -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { - BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); -} - -int NET_Connect(int s, struct sockaddr *addr, int addrlen) { - BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) ); -} - -int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { - BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); -} - -/* - * Wrapper for select(s, timeout). We are using select() on Mac OS due to Bug 7131399. - * Auto restarts with adjusted timeout if interrupted by - * signal other than our wakeup signal. - */ -int NET_Timeout(int s, long timeout) { - long prevtime = 0, newtime; - struct timeval t, *tp = &t; - fd_set fds; - fd_set* fdsp = NULL; - int allocated = 0; - threadEntry_t self; - fdEntry_t *fdEntry = getFdEntry(s); - - /* - * Check that fd hasn't been closed. - */ - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* - * Pick up current time as may need to adjust timeout - */ - if (timeout > 0) { - /* Timed */ - struct timeval now; - gettimeofday(&now, NULL); - prevtime = now.tv_sec * 1000 + now.tv_usec / 1000; - t.tv_sec = timeout / 1000; - t.tv_usec = (timeout % 1000) * 1000; - } else if (timeout < 0) { - /* Blocking */ - tp = 0; - } else { - /* Poll */ - t.tv_sec = 0; - t.tv_usec = 0; - } - - if (s < FD_SETSIZE) { - fdsp = &fds; - FD_ZERO(fdsp); - } else { - int length = (howmany(s+1, NFDBITS)) * sizeof(int); - fdsp = (fd_set *) calloc(1, length); - if (fdsp == NULL) { - return -1; // errno will be set to ENOMEM - } - allocated = 1; - } - FD_SET(s, fdsp); - - for(;;) { - int rv; - - /* - * call select on the fd. If interrupted by our wakeup signal - * errno will be set to EBADF. - */ - - startOp(fdEntry, &self); - rv = select(s+1, fdsp, 0, 0, tp); - endOp(fdEntry, &self); - - /* - * If interrupted then adjust timeout. If timeout - * has expired return 0 (indicating timeout expired). - */ - if (rv < 0 && errno == EINTR) { - if (timeout > 0) { - struct timeval now; - gettimeofday(&now, NULL); - newtime = now.tv_sec * 1000 + now.tv_usec / 1000; - timeout -= newtime - prevtime; - if (timeout <= 0) { - if (allocated != 0) - free(fdsp); - return 0; - } - prevtime = newtime; - t.tv_sec = timeout / 1000; - t.tv_usec = (timeout % 1000) * 1000; - } - } else { - if (allocated != 0) - free(fdsp); - return rv; - } - - } -}
--- a/jdk/src/java.base/unix/native/libnet/linux_close.c Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2001, 2013, 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <pthread.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <sys/poll.h> - -/* - * Stack allocated by thread when doing blocking operation - */ -typedef struct threadEntry { - pthread_t thr; /* this thread */ - struct threadEntry *next; /* next thread */ - int intr; /* interrupted */ -} threadEntry_t; - -/* - * Heap allocated during initialized - one entry per fd - */ -typedef struct { - pthread_mutex_t lock; /* fd lock */ - threadEntry_t *threads; /* threads blocked on fd */ -} fdEntry_t; - -/* - * Signal to unblock thread - */ -static int sigWakeup = (__SIGRTMAX - 2); - -/* - * The fd table and the number of file descriptors - */ -static fdEntry_t *fdTable; -static int fdCount; - -/* - * Null signal handler - */ -static void sig_wakeup(int sig) { -} - -/* - * Initialization routine (executed when library is loaded) - * Allocate fd tables and sets up signal handler. - */ -static void __attribute((constructor)) init() { - struct rlimit nbr_files; - sigset_t sigset; - struct sigaction sa; - - /* - * Allocate table based on the maximum number of - * file descriptors. - */ - getrlimit(RLIMIT_NOFILE, &nbr_files); - fdCount = nbr_files.rlim_max; - fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); - if (fdTable == NULL) { - fprintf(stderr, "library initialization failed - " - "unable to allocate file descriptor table - out of memory"); - abort(); - } - - /* - * Setup the signal handler - */ - sa.sa_handler = sig_wakeup; - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - sigaction(sigWakeup, &sa, NULL); - - sigemptyset(&sigset); - sigaddset(&sigset, sigWakeup); - sigprocmask(SIG_UNBLOCK, &sigset, NULL); -} - -/* - * Return the fd table for this fd or NULL is fd out - * of range. - */ -static inline fdEntry_t *getFdEntry(int fd) -{ - if (fd < 0 || fd >= fdCount) { - return NULL; - } - return &fdTable[fd]; -} - -/* - * Start a blocking operation :- - * Insert thread onto thread list for the fd. - */ -static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) -{ - self->thr = pthread_self(); - self->intr = 0; - - pthread_mutex_lock(&(fdEntry->lock)); - { - self->next = fdEntry->threads; - fdEntry->threads = self; - } - pthread_mutex_unlock(&(fdEntry->lock)); -} - -/* - * End a blocking operation :- - * Remove thread from thread list for the fd - * If fd has been interrupted then set errno to EBADF - */ -static inline void endOp - (fdEntry_t *fdEntry, threadEntry_t *self) -{ - int orig_errno = errno; - pthread_mutex_lock(&(fdEntry->lock)); - { - threadEntry_t *curr, *prev=NULL; - curr = fdEntry->threads; - while (curr != NULL) { - if (curr == self) { - if (curr->intr) { - orig_errno = EBADF; - } - if (prev == NULL) { - fdEntry->threads = curr->next; - } else { - prev->next = curr->next; - } - break; - } - prev = curr; - curr = curr->next; - } - } - pthread_mutex_unlock(&(fdEntry->lock)); - errno = orig_errno; -} - -/* - * Close or dup2 a file descriptor ensuring that all threads blocked on - * the file descriptor are notified via a wakeup signal. - * - * fd1 < 0 => close(fd2) - * fd1 >= 0 => dup2(fd1, fd2) - * - * Returns -1 with errno set if operation fails. - */ -static int closefd(int fd1, int fd2) { - int rv, orig_errno; - fdEntry_t *fdEntry = getFdEntry(fd2); - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* - * Lock the fd to hold-off additional I/O on this fd. - */ - pthread_mutex_lock(&(fdEntry->lock)); - - { - /* - * And close/dup the file descriptor - * (restart if interrupted by signal) - */ - do { - if (fd1 < 0) { - rv = close(fd2); - } else { - rv = dup2(fd1, fd2); - } - } while (rv == -1 && errno == EINTR); - - /* - * Send a wakeup signal to all threads blocked on this - * file descriptor. - */ - threadEntry_t *curr = fdEntry->threads; - while (curr != NULL) { - curr->intr = 1; - pthread_kill( curr->thr, sigWakeup ); - curr = curr->next; - } - } - - /* - * Unlock without destroying errno - */ - orig_errno = errno; - pthread_mutex_unlock(&(fdEntry->lock)); - errno = orig_errno; - - return rv; -} - -/* - * Wrapper for dup2 - same semantics as dup2 system call except - * that any threads blocked in an I/O system call on fd2 will be - * preempted and return -1/EBADF; - */ -int NET_Dup2(int fd, int fd2) { - if (fd < 0) { - errno = EBADF; - return -1; - } - return closefd(fd, fd2); -} - -/* - * Wrapper for close - same semantics as close system call - * except that any threads blocked in an I/O on fd will be - * preempted and the I/O system call will return -1/EBADF. - */ -int NET_SocketClose(int fd) { - return closefd(-1, fd); -} - -/************** Basic I/O operations here ***************/ - -/* - * Macro to perform a blocking IO operation. Restarts - * automatically if interrupted by signal (other than - * our wakeup signal) - */ -#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ - int ret; \ - threadEntry_t self; \ - fdEntry_t *fdEntry = getFdEntry(FD); \ - if (fdEntry == NULL) { \ - errno = EBADF; \ - return -1; \ - } \ - do { \ - startOp(fdEntry, &self); \ - ret = FUNC; \ - endOp(fdEntry, &self); \ - } while (ret == -1 && errno == EINTR); \ - return ret; \ -} - -int NET_Read(int s, void* buf, size_t len) { - BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); -} - -int NET_ReadV(int s, const struct iovec * vector, int count) { - BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); -} - -int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, - struct sockaddr *from, socklen_t *fromlen) { - BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) ); -} - -int NET_Send(int s, void *msg, int len, unsigned int flags) { - BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); -} - -int NET_WriteV(int s, const struct iovec * vector, int count) { - BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); -} - -int NET_SendTo(int s, const void *msg, int len, unsigned int - flags, const struct sockaddr *to, int tolen) { - BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); -} - -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { - BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); -} - -int NET_Connect(int s, struct sockaddr *addr, int addrlen) { - BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) ); -} - -int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { - BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); -} - -/* - * Wrapper for poll(s, timeout). - * Auto restarts with adjusted timeout if interrupted by - * signal other than our wakeup signal. - */ -int NET_Timeout(int s, long timeout) { - long prevtime = 0, newtime; - struct timeval t; - fdEntry_t *fdEntry = getFdEntry(s); - - /* - * Check that fd hasn't been closed. - */ - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* - * Pick up current time as may need to adjust timeout - */ - if (timeout > 0) { - gettimeofday(&t, NULL); - prevtime = t.tv_sec * 1000 + t.tv_usec / 1000; - } - - for(;;) { - struct pollfd pfd; - int rv; - threadEntry_t self; - - /* - * Poll the fd. If interrupted by our wakeup signal - * errno will be set to EBADF. - */ - pfd.fd = s; - pfd.events = POLLIN | POLLERR; - - startOp(fdEntry, &self); - rv = poll(&pfd, 1, timeout); - endOp(fdEntry, &self); - - /* - * If interrupted then adjust timeout. If timeout - * has expired return 0 (indicating timeout expired). - */ - if (rv < 0 && errno == EINTR) { - if (timeout > 0) { - gettimeofday(&t, NULL); - newtime = t.tv_sec * 1000 + t.tv_usec / 1000; - timeout -= newtime - prevtime; - if (timeout <= 0) { - return 0; - } - prevtime = newtime; - } - } else { - return rv; - } - - } -}
--- a/jdk/src/java.base/unix/native/libnet/solaris_close.c Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <errno.h> -#include <sys/socket.h> -#include <stropts.h> -#include <unistd.h> - -/* Support for restartable system calls on Solaris. */ - -#define RESTARTABLE_RETURN_INT(_cmd) do { \ - int _result; \ - if (1) { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ - return _result; \ - } \ -} while(0) - -int NET_Read(int s, void* buf, size_t len) { - RESTARTABLE_RETURN_INT(recv(s, buf, len, 0)); -} - -int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, - struct sockaddr *from, socklen_t *fromlen) { - RESTARTABLE_RETURN_INT(recvfrom(s, buf, len, flags, from, fromlen)); -} - -int NET_ReadV(int s, const struct iovec * vector, int count) { - RESTARTABLE_RETURN_INT(readv(s, vector, count)); -} - -int NET_WriteV(int s, const struct iovec * vector, int count) { - RESTARTABLE_RETURN_INT(writev(s, vector, count)); -} - -int NET_Send(int s, void *msg, int len, unsigned int flags) { - RESTARTABLE_RETURN_INT(send(s, msg, len, flags)); -} - -int NET_SendTo(int s, const void *msg, int len, unsigned int flags, - const struct sockaddr *to, int tolen) { - RESTARTABLE_RETURN_INT(sendto(s, msg, len, flags, to, tolen)); -} - -int NET_Connect(int s, struct sockaddr *addr, int addrlen) { - RESTARTABLE_RETURN_INT(connect(s, addr, addrlen)); -} - -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { - RESTARTABLE_RETURN_INT(accept(s, addr, addrlen)); -} - -int NET_SocketClose(int fd) { - return close(fd); -} - -int NET_Dup2(int fd, int fd2) { - return dup2(fd, fd2); -} - -int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { - RESTARTABLE_RETURN_INT(poll(ufds, nfds, timeout)); -} - -int NET_Timeout(int s, long timeout) { - int result; - struct timeval t; - long prevtime, newtime; - struct pollfd pfd; - pfd.fd = s; - pfd.events = POLLIN; - - if (timeout > 0) { - gettimeofday(&t, NULL); - prevtime = (t.tv_sec * 1000) + t.tv_usec / 1000; - } - - for(;;) { - result = poll(&pfd, 1, timeout); - if (result < 0 && errno == EINTR) { - if (timeout > 0) { - gettimeofday(&t, NULL); - newtime = (t.tv_sec * 1000) + t.tv_usec /1000; - timeout -= newtime - prevtime; - if (timeout <= 0) - return 0; - prevtime = newtime; - } - } else { - return result; - } - } -}
--- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Thu Jan 29 15:35:29 2015 -0800 @@ -48,6 +48,8 @@ isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/net/InetAddress;I)V"); + initInetAddressIDs(env); + // implement read timeout with select. isRcvTimeoutSupported = 0; } @@ -294,6 +296,8 @@ return -1; } + SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); + ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); (*env)->SetObjectArrayElement(env, isaa, 0, isa);
--- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c Thu Jan 29 15:35:29 2015 -0800 @@ -699,6 +699,7 @@ } return; } + SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0); (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd); if (him.him.sa_family == AF_INET) {
--- a/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c Thu Jan 29 15:35:29 2015 -0800 @@ -105,6 +105,7 @@ return IOS_THROWN; } + SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); (*env)->SetIntField(env, newfdo, fd_fdID, newfd); remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port); CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java Thu Jan 29 15:35:29 2015 -0800 @@ -913,9 +913,9 @@ private static String unquote(String s) { s = s.trim(); - if (s.isEmpty()) return s; - if (s.charAt(0) == '"' && s.charAt(s.length()-1) == '"' || - s.charAt(0) == '\'' && s.charAt(s.length()-1) == '\'') { + if (s.length() >= 2 && + ((s.charAt(0) == '"' && s.charAt(s.length()-1) == '"') || + (s.charAt(0) == '\'' && s.charAt(s.length()-1) == '\''))) { s = s.substring(1, s.length()-1).trim(); } return s;
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java Thu Jan 29 15:35:29 2015 -0800 @@ -62,7 +62,8 @@ throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); } - for (int i = 1; i < 6; i++) { + // We allow KDC to return a non-forwardable ticket if request has -f + for (int i = 2; i < 6; i++) { if (req.reqBody.kdcOptions.get(i) != rep.encKDCRepPart.flags.get(i)) { if (Krb5.DEBUG) {
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java Thu Jan 29 15:35:29 2015 -0800 @@ -149,19 +149,11 @@ ctime = KerberosTime.now(); // check if they are valid arguments. The optional fields - // should be consistent with settings in KDCOptions. - - // TODO: Is this necessary? If the TGT is not FORWARDABLE, - // you can still request for a FORWARDABLE ticket, just the - // KDC will give you a non-FORWARDABLE one. Even if you - // cannot use the ticket expected, it still contains info. - // This means there will be problem later. We already have - // flags check in KrbTgsRep. Of course, sometimes the KDC - // will not issue the ticket at all. + // should be consistent with settings in KDCOptions. if (options.get(KDCOptions.FORWARDABLE) && (!(asCreds.flags.get(Krb5.TKT_OPTS_FORWARDABLE)))) { - throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); + options.set(KDCOptions.FORWARDABLE, false); } if (options.get(KDCOptions.FORWARDED)) { if (!(asCreds.flags.get(KDCOptions.FORWARDABLE)))
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java Thu Jan 29 15:35:29 2015 -0800 @@ -58,6 +58,9 @@ // TODO: we do not support kerberos referral now throw new KrbException("Cross realm impersonation not supported"); } + if (!ccreds.isForwardable()) { + throw new KrbException("S4U2self needs a FORWARDABLE ticket"); + } KrbTgsReq req = new KrbTgsReq( ccreds, ccreds.getClient(), @@ -68,6 +71,9 @@ if (!creds.getClient().equals(client)) { throw new KrbException("S4U2self request not honored by KDC"); } + if (!creds.isForwardable()) { + throw new KrbException("S4U2self ticket must be FORWARDABLE"); + } return creds; }
--- a/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c Thu Jan 29 15:35:29 2015 -0800 @@ -316,11 +316,12 @@ if (isaCls == 0) { jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress"); CHECK_NULL(c); + isaCtrID = (*env)->GetMethodID(env, c, "<init>", + "(Ljava/net/InetAddress;I)V"); + CHECK_NULL(isaCtrID); isaCls = (*env)->NewGlobalRef(env, c); CHECK_NULL(isaCls); (*env)->DeleteLocalRef(env, c); - isaCtrID = (*env)->GetMethodID(env, isaCls, "<init>", - "(Ljava/net/InetAddress;I)V"); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.auth/solaris/native/libjaas/Solaris.c Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2000, 2013, 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. + */ + +#include <jni.h> +#include "com_sun_security_auth_module_SolarisSystem.h" +#include <stdio.h> +#include <pwd.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <pwd.h> + +static void throwIllegalArgumentException(JNIEnv *env, const char *msg) { + jclass clazz = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); + if (clazz != NULL) + (*env)->ThrowNew(env, clazz, msg); +} + +JNIEXPORT void JNICALL +Java_com_sun_security_auth_module_SolarisSystem_getSolarisInfo + (JNIEnv *env, jobject obj) { + + int i; + char pwd_buf[1024]; + struct passwd pwd; + jsize numSuppGroups = getgroups(0, NULL); + jfieldID fid; + jstring jstr; + jlongArray jgroups; + jlong *jgroupsAsArray; + gid_t *groups; + jclass cls; + + groups = (gid_t *)calloc(numSuppGroups, sizeof(gid_t)); + + if (groups == NULL) { + jclass cls = (*env)->FindClass(env,"java/lang/OutOfMemoryError"); + if (cls != NULL) + (*env)->ThrowNew(env, cls, NULL); + return; + } + + cls = (*env)->GetObjectClass(env, obj); + + memset(pwd_buf, 0, sizeof(pwd_buf)); + if (getpwuid_r(getuid(), &pwd, pwd_buf, sizeof(pwd_buf)) != NULL && + getgroups(numSuppGroups, groups) != -1) { + + /* + * set username + */ + fid = (*env)->GetFieldID(env, cls, "username", "Ljava/lang/String;"); + if (fid == 0) { + (*env)->ExceptionClear(env); + throwIllegalArgumentException(env, "invalid field: username"); + goto cleanupAndReturn; + } + jstr = (*env)->NewStringUTF(env, pwd.pw_name); + if (jstr == NULL) { + goto cleanupAndReturn; + } + (*env)->SetObjectField(env, obj, fid, jstr); + + /* + * set uid + */ + fid = (*env)->GetFieldID(env, cls, "uid", "J"); + if (fid == 0) { + (*env)->ExceptionClear(env); + throwIllegalArgumentException(env, "invalid field: uid"); + goto cleanupAndReturn; + } + (*env)->SetLongField(env, obj, fid, pwd.pw_uid); + + /* + * set gid + */ + fid = (*env)->GetFieldID(env, cls, "gid", "J"); + if (fid == 0) { + (*env)->ExceptionClear(env); + throwIllegalArgumentException(env, "invalid field: gid"); + goto cleanupAndReturn; + } + (*env)->SetLongField(env, obj, fid, pwd.pw_gid); + + /* + * set supplementary groups + */ + fid = (*env)->GetFieldID(env, cls, "groups", "[J"); + if (fid == 0) { + (*env)->ExceptionClear(env); + throwIllegalArgumentException(env, "invalid field: groups"); + goto cleanupAndReturn; + } + + jgroups = (*env)->NewLongArray(env, numSuppGroups); + if (jgroups == NULL) { + goto cleanupAndReturn; + } + jgroupsAsArray = (*env)->GetLongArrayElements(env, jgroups, 0); + if (jgroupsAsArray == NULL) { + goto cleanupAndReturn; + } + for (i = 0; i < numSuppGroups; i++) + jgroupsAsArray[i] = groups[i]; + (*env)->ReleaseLongArrayElements(env, jgroups, jgroupsAsArray, 0); + (*env)->SetObjectField(env, obj, fid, jgroups); + } +cleanupAndReturn: + free(groups); + + return; +}
--- a/jdk/src/jdk.security.auth/unix/native/libjaas/Solaris.c Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2000, 2013, 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. - */ - -#include <jni.h> -#include "com_sun_security_auth_module_SolarisSystem.h" -#include <stdio.h> -#include <pwd.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <pwd.h> - -static void throwIllegalArgumentException(JNIEnv *env, const char *msg) { - jclass clazz = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); - if (clazz != NULL) - (*env)->ThrowNew(env, clazz, msg); -} - -JNIEXPORT void JNICALL -Java_com_sun_security_auth_module_SolarisSystem_getSolarisInfo - (JNIEnv *env, jobject obj) { - - int i; - char pwd_buf[1024]; - struct passwd pwd; - jsize numSuppGroups = getgroups(0, NULL); - jfieldID fid; - jstring jstr; - jlongArray jgroups; - jlong *jgroupsAsArray; - gid_t *groups; - jclass cls; - - groups = (gid_t *)calloc(numSuppGroups, sizeof(gid_t)); - - if (groups == NULL) { - jclass cls = (*env)->FindClass(env,"java/lang/OutOfMemoryError"); - if (cls != NULL) - (*env)->ThrowNew(env, cls, NULL); - return; - } - - cls = (*env)->GetObjectClass(env, obj); - - memset(pwd_buf, 0, sizeof(pwd_buf)); - if (getpwuid_r(getuid(), &pwd, pwd_buf, sizeof(pwd_buf)) != NULL && - getgroups(numSuppGroups, groups) != -1) { - - /* - * set username - */ - fid = (*env)->GetFieldID(env, cls, "username", "Ljava/lang/String;"); - if (fid == 0) { - (*env)->ExceptionClear(env); - throwIllegalArgumentException(env, "invalid field: username"); - goto cleanupAndReturn; - } - jstr = (*env)->NewStringUTF(env, pwd.pw_name); - if (jstr == NULL) { - goto cleanupAndReturn; - } - (*env)->SetObjectField(env, obj, fid, jstr); - - /* - * set uid - */ - fid = (*env)->GetFieldID(env, cls, "uid", "J"); - if (fid == 0) { - (*env)->ExceptionClear(env); - throwIllegalArgumentException(env, "invalid field: uid"); - goto cleanupAndReturn; - } - (*env)->SetLongField(env, obj, fid, pwd.pw_uid); - - /* - * set gid - */ - fid = (*env)->GetFieldID(env, cls, "gid", "J"); - if (fid == 0) { - (*env)->ExceptionClear(env); - throwIllegalArgumentException(env, "invalid field: gid"); - goto cleanupAndReturn; - } - (*env)->SetLongField(env, obj, fid, pwd.pw_gid); - - /* - * set supplementary groups - */ - fid = (*env)->GetFieldID(env, cls, "groups", "[J"); - if (fid == 0) { - (*env)->ExceptionClear(env); - throwIllegalArgumentException(env, "invalid field: groups"); - goto cleanupAndReturn; - } - - jgroups = (*env)->NewLongArray(env, numSuppGroups); - if (jgroups == NULL) { - goto cleanupAndReturn; - } - jgroupsAsArray = (*env)->GetLongArrayElements(env, jgroups, 0); - if (jgroupsAsArray == NULL) { - goto cleanupAndReturn; - } - for (i = 0; i < numSuppGroups; i++) - jgroupsAsArray[i] = groups[i]; - (*env)->ReleaseLongArrayElements(env, jgroups, jgroupsAsArray, 0); - (*env)->SetObjectField(env, obj, fid, jgroups); - } -cleanupAndReturn: - free(groups); - - return; -}
--- a/jdk/test/ProblemList.txt Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/ProblemList.txt Thu Jan 29 15:35:29 2015 -0800 @@ -128,9 +128,6 @@ # jdk_instrument -# 8058536 -java/lang/instrument/NativeMethodPrefixAgent.java generic-all - # 8061177 java/lang/instrument/RedefineBigClass.sh generic-all java/lang/instrument/RetransformBigClass.sh generic-all @@ -246,6 +243,9 @@ # 8062758 java/security/Security/ClassLoaderDeadlock/Deadlock2.sh generic-all +# 8026393 +sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java generic-all + ############################################################################ # jdk_sound
--- a/jdk/test/TEST.groups Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/TEST.groups Thu Jan 29 15:35:29 2015 -0800 @@ -628,7 +628,6 @@ sun/net/www/protocol/http \ java/io/BufferedReader/Lines.java \ java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java \ - java/lang/CharSequence/DefaultTest.java \ java/lang/IntegralPrimitiveToString.java \ java/lang/PrimitiveSumMinMaxTest.java \ java/lang/String/StringJoinTest.java \
--- a/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java Thu Jan 29 15:35:29 2015 -0800 @@ -50,8 +50,9 @@ } ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); - ClassLoader loader = new URLClassLoader(((URLClassLoader) systemLoader).getURLs(), - systemLoader.getParent()); + URL testClassesURL = new File(System.getProperty("test.classes")).toURI().toURL(); + ClassLoader loader = new URLClassLoader(new URL[] { testClassesURL } , + systemLoader.getParent()); Class<? extends ObjectOutputStream> cl = Class.forName(SubclassOfOOS.class.getName(), false, loader).asSubclass(ObjectOutputStream.class);
--- a/jdk/test/java/io/Serializable/subclassGC/security.policy Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/java/io/Serializable/subclassGC/security.policy Thu Jan 29 15:35:29 2015 -0800 @@ -2,5 +2,7 @@ grant { permission java.lang.RuntimePermission "createClassLoader"; permission java.lang.RuntimePermission "getClassLoader"; + permission java.util.PropertyPermission "test.classes", "read"; + permission java.io.FilePermission "<<ALL FILES>>", "read"; };
--- a/jdk/test/java/lang/CharSequence/DefaultTest.java Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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. - * - * 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. - */ - -import java.util.Arrays; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.PrimitiveIterator; -import java.util.Spliterator; -import java.util.stream.Collectors; - -import org.testng.annotations.Test; - -import static org.testng.Assert.*; - -/* - * @test - * @summary Unit test for CharSequence default methods - * @bug 8012665 8025002 - * @run testng DefaultTest - */ - -@Test(groups = "lib") -public class DefaultTest { - - @Test(expectedExceptions = NoSuchElementException.class) - public void testEmptyChars() { - PrimitiveIterator.OfInt s = "".chars().iterator(); - assertFalse(s.hasNext()); - int ch = s.nextInt(); - } - - public void testSimpleChars() { - List<Integer> list = "abc".chars().boxed().collect(Collectors.toList()); - assertEquals(list, Arrays.asList((int) 'a', (int) 'b', (int) 'c')); - } - - public void testCodePointsCharacteristics() { - Spliterator.OfInt s = "".codePoints().spliterator(); - assertFalse(s.hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED)); - assertTrue(s.hasCharacteristics(Spliterator.ORDERED)); - } - - @Test(expectedExceptions = NoSuchElementException.class) - public void testEmptyCodePoints() { - PrimitiveIterator.OfInt s = "".codePoints().iterator(); - assertFalse(s.hasNext()); - int cp = s.nextInt(); - } - - public void testSimpleCodePoints() { - List<Integer> list = "abc".codePoints().boxed().collect(Collectors.toList()); - assertEquals(list, Arrays.asList((int)'a', (int)'b', (int)'c')); - } - - public void testUndefCodePoints() { - List<Integer> list = "X\ufffeY".codePoints().boxed().collect(Collectors.toList()); - assertEquals(list, Arrays.asList((int)'X', 0xFFFE, (int)'Y')); - } - - public void testSurrogatePairing() { - // U+1D11E = MUSICAL SYMBOL G CLEF - // equivalent to surrogate pair U+D834 U+DD1E - List<Integer> list; - final int GCLEF = 0x1d11e; - - list = "\ud834\udd1e".codePoints().boxed().collect(Collectors.toList()); - assertEquals(list, Arrays.asList(GCLEF)); - list = "A\ud834\udd1e".codePoints().boxed().collect(Collectors.toList()); - assertEquals(list, Arrays.asList((int)'A', GCLEF)); - list = "\ud834\udd1eB".codePoints().boxed().collect(Collectors.toList()); - assertEquals(list, Arrays.asList(GCLEF, (int)'B')); - list = "X\ud834\udd1eY".codePoints().boxed().collect(Collectors.toList()); - assertEquals(list, Arrays.asList((int)'X', GCLEF, (int)'Y')); - } - - public void testUndefUnpaired() { - List<Integer> list = "W\udd1eX\ud834Y\ufffeZ".codePoints().boxed().collect(Collectors.toList()); - assertEquals(list, Arrays.asList( - (int)'W', 0xdd1e, (int)'X', 0xd834, (int)'Y', 0xfffe, (int)'Z')); - } -}
--- a/jdk/test/java/lang/ProcessBuilder/Basic.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/java/lang/ProcessBuilder/Basic.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -26,7 +26,7 @@ * @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689 * 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313 * 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958 - * 4947220 7018606 7034570 4244896 5049299 8003488 + * 4947220 7018606 7034570 4244896 5049299 8003488 8054494 * @summary Basic tests for Process and Environment Variable code * @run main/othervm/timeout=300 Basic * @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=fork Basic @@ -2042,7 +2042,7 @@ final Object deferred; Class<?> c = s.getClass(); if (c.getName().equals( - "java.lang.UNIXProcess$DeferredCloseInputStream")) + "java.lang.ProcessImpl$DeferredCloseInputStream")) { deferred = s; } else { @@ -2059,13 +2059,11 @@ Thread.yield(); } } else if (s instanceof BufferedInputStream) { - Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - Unsafe unsafe = (Unsafe)f.get(null); - - while (unsafe.tryMonitorEnter(s)) { - unsafe.monitorExit(s); - Thread.sleep(1); + // Wait until after the s.read occurs in "thread" by + // checking when the input stream monitor is acquired + // (BufferedInputStream.read is synchronized) + while (!isLocked(s, 10)) { + Thread.sleep(100); } } p.destroy(); @@ -2565,4 +2563,21 @@ catch (Throwable t) { if (k.isAssignableFrom(t.getClass())) pass(); else unexpected(t);}} + + static boolean isLocked(final Object monitor, final long millis) throws InterruptedException { + return new Thread() { + volatile boolean unlocked; + + @Override + public void run() { + synchronized (monitor) { unlocked = true; } + } + + boolean isLocked() throws InterruptedException { + start(); + join(millis); + return !unlocked; + } + }.isLocked(); + } }
--- a/jdk/test/java/lang/ref/OOMEInReferenceHandler.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/java/lang/ref/OOMEInReferenceHandler.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -25,7 +25,7 @@ * @test * @bug 7038914 8016341 * @summary Verify that the reference handler does not die after an OOME allocating the InterruptedException object - * @run main/othervm -Xmx24M -XX:-UseTLAB OOMEInReferenceHandler + * @run main/othervm -XX:-UseGCOverheadLimit -Xmx24M -XX:-UseTLAB OOMEInReferenceHandler * @author peter.levart@gmail.com */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/net/ServerSocket/AcceptInheritHandle.java Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015, 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. + * + * 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. + */ + +/* + * @test + * @bug 8067105 + * @summary Socket returned by ServerSocket.accept() is inherited by child process on Windows + * @author Chris Hegarty + */ + +import java.io.*; +import java.net.*; +import java.nio.channels.ServerSocketChannel; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public class AcceptInheritHandle { + + enum ServerSocketProducer { + JAVA_NET(() -> { + try { + return new ServerSocket(); } + catch(IOException x) { + throw new UncheckedIOException(x); + } + }), + NIO_CHANNELS(() -> { + try { + return ServerSocketChannel.open().socket(); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + + final Supplier<ServerSocket> supplier; + ServerSocketProducer(Supplier<ServerSocket> supplier) { + this.supplier = supplier; + } + Supplier<ServerSocket> supplier () { return supplier; } + } + + static final String JAVA = System.getProperty("java.home") + + File.separator + "bin" + File.separator + "java"; + + static final String CLASSPATH = System.getProperty("java.class.path"); + + public static void main(String[] args) throws Exception { + if (args.length == 1) + server(ServerSocketProducer.valueOf(args[0])); + else + mainEntry(); + } + + static void mainEntry() throws Exception { + testJavaNetServerSocket(); + testNioServerSocketChannel(); + } + + static void testJavaNetServerSocket() throws Exception { + test(ServerSocketProducer.JAVA_NET); + test(ServerSocketProducer.JAVA_NET, "-Djava.net.preferIPv4Stack=true"); + } + static void testNioServerSocketChannel() throws Exception { + test(ServerSocketProducer.NIO_CHANNELS); + } + + static void test(ServerSocketProducer ssp, String... sysProps) throws Exception { + System.out.println("\nStarting test for " + ssp.name()); + + List<String> commands = new ArrayList<>(); + commands.add(JAVA); + for (String prop : sysProps) + commands.add(prop); + commands.add("-cp"); + commands.add(CLASSPATH); + commands.add("AcceptInheritHandle"); + commands.add(ssp.name()); + + System.out.println("Executing: "+ commands); + ProcessBuilder pb = new ProcessBuilder(commands); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + Process serverProcess = pb.start(); + DataInputStream dis = new DataInputStream(serverProcess.getInputStream()); + + int port = dis.readInt(); + System.out.println("Server process listening on " + port + ", connecting..."); + + Socket socket = new Socket("localhost", port); + String s = dis.readUTF(); + System.out.println("Server process said " + s); + + serverProcess.destroy(); + serverProcess.waitFor(30, TimeUnit.SECONDS); + System.out.println("serverProcess exitCode:" + serverProcess.exitValue()); + + try { + socket.setSoTimeout(10 * 1000); + socket.getInputStream().read(); + } catch (SocketTimeoutException x) { + // failed + throw new RuntimeException("Failed: should get reset, not " + x); + } catch (SocketException x) { + System.out.println("Expected:" + x); + } + } + + static void server(ServerSocketProducer producer) throws Exception { + try (ServerSocket ss = producer.supplier().get()) { + ss.bind(new InetSocketAddress(0)); + int port = ss.getLocalPort(); + DataOutputStream dos = new DataOutputStream(System.out); + dos.writeInt(port); + dos.flush(); + + ss.accept(); // do not close + + Runtime.getRuntime().exec("sleep 20"); + Thread.sleep(3 * 1000); + + dos.writeUTF("kill me!"); + dos.flush(); + Thread.sleep(30 * 1000); + } + } +}
--- a/jdk/test/java/net/Socket/GetLocalAddress.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/java/net/Socket/GetLocalAddress.java Thu Jan 29 15:35:29 2015 -0800 @@ -23,7 +23,7 @@ /* * @test - * @bug 4106601 8026245 + * @bug 4106601 8026245 8071424 * @run main/othervm GetLocalAddress * @run main/othervm -Djava.net.preferIPv4Stack=true GetLocalAddress * @run main/othervm -Djava.net.preferIPv6Addresses=true GetLocalAddress @@ -39,6 +39,8 @@ static int port; public static void main(String args[]) throws Exception { + testBindNull(); + boolean error = true; int linger = 65546; int value = 0; @@ -66,4 +68,18 @@ } } + static void testBindNull() throws Exception { + try (Socket soc = new Socket()) { + soc.bind(null); + if (!soc.isBound()) + throw new RuntimeException( + "should be bound after bind(null)"); + if (soc.getLocalPort() <= 0) + throw new RuntimeException( + "bind(null) failed, local port: " + soc.getLocalPort()); + if (soc.getLocalAddress() == null) + throw new RuntimeException( + "bind(null) failed, local address is null"); + } + } }
--- a/jdk/test/java/util/ResourceBundle/Bug6287579.java Wed Jan 28 16:45:45 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2007, 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. - * - * 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. - */ -/* - * @test - * @bug 6287579 - * @summary Make sure that getContents() of ListResourceBundle subclasses is 'protected' - * and returns a different Object[]][] instance in each invocation. - */ - -import java.lang.reflect.*; -import java.util.*; - -public class Bug6287579 { - static final Locale ROOT = new Locale(""); - - static final String[] baseNames = { - "sun.text.resources.BreakIteratorInfo", - "sun.text.resources.FormatData", - "sun.text.resources.CollationData", - "sun.util.resources.LocaleNames", - "sun.util.resources.TimeZoneNames", - - // Make sure the properties-to-class conversion tool generates - // the proper getContents(). - "sun.awt.resources.awt", - }; - - public static void main(String[] args) throws Exception { - int errors = 0; - - List<Locale> locales = new ArrayList<Locale>(); - locales.addAll(Arrays.asList(Locale.getAvailableLocales())); - locales.add(ROOT); - - for (Locale locale : locales) { - for (String base : baseNames) { - String className = getResourceName(base, locale); - errors += checkGetContents(className); - } - } - if (errors > 0) { - throw new RuntimeException(errors + " errors found"); - } - } - - static int checkGetContents(String className) throws Exception { - int err = 0; - try { - Class clazz = Class.forName(className); - Method getContentsMethod = clazz.getDeclaredMethod("getContents", - (Class[]) null); - if (!Modifier.isProtected(getContentsMethod.getModifiers())) { - System.err.println(className + ": not protected"); - err++; - } - getContentsMethod.setAccessible(true); - Object bundle = clazz.newInstance(); - Object o1 = getContentsMethod.invoke(bundle, (Object[]) null); - Object o2 = getContentsMethod.invoke(bundle, (Object[]) null); - if (o1 == o2) { - System.err.println(className + ": same instance returned"); - err++; - } - } catch (ClassNotFoundException ce) { - // Skip nonexistent classes - } catch (NoSuchMethodException me) { - System.out.println(className + ": no declared getContents()"); - } - return err; - } - - static String getResourceName(String base, Locale locale) { - if (locale.equals(ROOT)) { - return base; - } - StringBuilder sb = new StringBuilder(base); - sb.append('_').append(locale.getLanguage()); - if (locale.getCountry().length() > 0 - || locale.getVariant().length() > 0) { - sb.append('_').append(locale.getCountry()); - } - if (locale.getVariant().length() > 0) { - sb.append('_').append(locale.getVariant()); - } - return sb.toString(); - } -}
--- a/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -23,7 +23,7 @@ /** * @test - * @bug 8020156 8020009 8022326 8012913 8024405 8024408 + * @bug 8020156 8020009 8022326 8012913 8024405 8024408 8071477 * @run testng SpliteratorCharacteristics */ @@ -59,6 +59,57 @@ @Test public class SpliteratorCharacteristics { + public void testSpliteratorFromCharSequence() { + class CharSequenceImpl implements CharSequence { + final String s; + + public CharSequenceImpl(String s) { + this.s = s; + } + + @Override + public int length() { + return s.length(); + } + + @Override + public char charAt(int index) { + return s.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return s.subSequence(start, end); + } + + @Override + public String toString() { + return s; + } + } + + CharSequence cs = "A"; + Spliterator.OfInt s = cs.chars().spliterator(); + assertCharacteristics(s, Spliterator.IMMUTABLE | Spliterator.ORDERED | + Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.CONCURRENT); + s = cs.codePoints().spliterator(); + assertCharacteristics(s, Spliterator.IMMUTABLE | Spliterator.ORDERED); + assertHasNotCharacteristics(s, Spliterator.CONCURRENT); + + for (CharSequence c : Arrays.asList(new CharSequenceImpl("A"), + new StringBuilder("A"), + new StringBuffer("A"))) { + s = cs.chars().spliterator(); + assertCharacteristics(s, Spliterator.ORDERED | + Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.CONCURRENT); + s = cs.codePoints().spliterator(); + assertCharacteristics(s, Spliterator.ORDERED); + assertHasNotCharacteristics(s, Spliterator.CONCURRENT); + } + } + public void testSpliteratorFromCollection() { List<Integer> l = Arrays.asList(1, 2, 3, 4);
--- a/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -25,7 +25,7 @@ * @test * @summary Spliterator traversing and splitting tests * @run testng SpliteratorTraversingAndSplittingTest - * @bug 8020016 + * @bug 8020016 8071477 */ import org.testng.annotations.DataProvider; @@ -85,7 +85,38 @@ @Test public class SpliteratorTraversingAndSplittingTest { - private static List<Integer> SIZES = Arrays.asList(0, 1, 10, 100, 1000); + private static final List<Integer> SIZES = Arrays.asList(0, 1, 10, 100, 1000); + + private static final String LOW = new String(new char[] {Character.MIN_LOW_SURROGATE}); + private static final String HIGH = new String(new char[] {Character.MIN_HIGH_SURROGATE}); + private static final String HIGH_LOW = HIGH + LOW; + private static final String CHAR_HIGH_LOW = "A" + HIGH_LOW; + private static final String HIGH_LOW_CHAR = HIGH_LOW + "A"; + private static final String CHAR_HIGH_LOW_CHAR = "A" + HIGH_LOW + "A"; + + private static final List<String> STRINGS = generateTestStrings(); + + private static List<String> generateTestStrings() { + List<String> strings = new ArrayList<>(); + for (int n : Arrays.asList(1, 2, 3, 16, 17)) { + strings.add(generate("A", n)); + strings.add(generate(LOW, n)); + strings.add(generate(HIGH, n)); + strings.add(generate(HIGH_LOW, n)); + strings.add(generate(CHAR_HIGH_LOW, n)); + strings.add(generate(HIGH_LOW_CHAR, n)); + strings.add(generate(CHAR_HIGH_LOW_CHAR, n)); + } + return strings; + } + + private static String generate(String s, int n) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + sb.append(s); + } + return sb.toString(); + } private static class SpliteratorDataBuilder<T> { List<Object[]> data; @@ -564,6 +595,60 @@ } } + private static class SpliteratorOfIntCharDataBuilder { + List<Object[]> data; + + String s; + + List<Integer> expChars; + + List<Integer> expCodePoints; + + SpliteratorOfIntCharDataBuilder(List<Object[]> data, String s) { + this.data = data; + this.s = s; + this.expChars = transform(s, false); + this.expCodePoints = transform(s, true); + } + + static List<Integer> transform(String s, boolean toCodePoints) { + List<Integer> l = new ArrayList<>(); + + if (!toCodePoints) { + for (int i = 0; i < s.length(); i++) { + l.add((int) s.charAt(i)); + } + } + else { + for (int i = 0; i < s.length();) { + char c1 = s.charAt(i++); + int cp = c1; + if (Character.isHighSurrogate(c1) && i < s.length()) { + char c2 = s.charAt(i); + if (Character.isLowSurrogate(c2)) { + i++; + cp = Character.toCodePoint(c1, c2); + } + } + l.add(cp); + } + } + return l; + } + + void add(String description, Function<String, CharSequence> f) { + description = description.replace("%s", s); + { + Supplier<Spliterator.OfInt> supplier = () -> f.apply(s).chars().spliterator(); + data.add(new Object[]{description + ".chars().spliterator()", expChars, supplier}); + } + { + Supplier<Spliterator.OfInt> supplier = () -> f.apply(s).codePoints().spliterator(); + data.add(new Object[]{description + ".codePoints().spliterator()", expCodePoints, supplier}); + } + } + } + static Object[][] spliteratorOfIntDataProvider; @DataProvider(name = "Spliterator.OfInt") @@ -615,6 +700,43 @@ () -> new IntSpliteratorFromArray(exp)); } + // Class for testing default methods + class CharSequenceImpl implements CharSequence { + final String s; + + public CharSequenceImpl(String s) { + this.s = s; + } + + @Override + public int length() { + return s.length(); + } + + @Override + public char charAt(int index) { + return s.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return s.subSequence(start, end); + } + + @Override + public String toString() { + return s; + } + } + + for (String string : STRINGS) { + SpliteratorOfIntCharDataBuilder cdb = new SpliteratorOfIntCharDataBuilder(data, string); + cdb.add("\"%s\"", s -> s); + cdb.add("new CharSequenceImpl(\"%s\")", CharSequenceImpl::new); + cdb.add("new StringBuilder(\"%s\")", StringBuilder::new); + cdb.add("new StringBuffer(\"%s\")", StringBuffer::new); + } + return spliteratorOfIntDataProvider = data.toArray(new Object[0][]); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/jaxp/transform/8062923/XslSubstringTest.java Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, 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. + * + * 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. + */ + +/** + * @test + * @bug 8062923 8062924 + * @run testng XslSubstringTest + * @summary Test xsl substring function with negative, Inf and + * NaN length and few other use cases + */ + +import java.io.StringReader; +import java.io.StringWriter; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.Test; + +public class XslSubstringTest { + + final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test></test>"; + final String xslPre = "<xsl:stylesheet version='1.0'" + + " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" + + "<xsl:output method='xml' indent='yes' omit-xml-declaration='yes'/>" + + "<xsl:template match='/'><t>"; + final String xslPost = "</t></xsl:template></xsl:stylesheet>"; + + private String testTransform(String xsl) throws Exception { + //Prepare sources for transormation + Source src = new StreamSource(new StringReader(xml)); + Source xslsrc = new StreamSource(new StringReader(xslPre + xsl + xslPost)); + //Create factory, template and transformer + TransformerFactory tf = TransformerFactory.newInstance(); + Templates tmpl = tf.newTemplates(xslsrc); + Transformer t = tmpl.newTransformer(); + //Prepare output stream + StringWriter xmlResultString = new StringWriter(); + StreamResult xmlResultStream = new StreamResult(xmlResultString); + //Transform + t.transform(src, xmlResultStream); + return xmlResultString.toString().trim(); + } + + @Test + public void test8062923() throws Exception { + assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2,-1)\"/>|"), + "<t>||</t>"); + } + + @Test + public void test8062924() throws Exception { + assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2,-1 div 0)\"/>|"), + "<t>||</t>"); + } + + @Test + public void testGeneral1() throws Exception { + assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2, 1)\"/>|"), + "<t>|s|</t>"); + } + + @Test + public void testGeneral2() throws Exception { + assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2, 1 div 0)\"/>|"), + "<t>|sdf|</t>"); + } + + @Test + public void testGeneral3() throws Exception { + assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2, -0 div 0)\"/>|"), + "<t>||</t>"); + } + + @Test + public void testGeneral4() throws Exception { + assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2, 0 div 0)\"/>|"), + "<t>||</t>"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/ws/8046817/GenerateEnumSchema.java Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +/* + * @test + * @bug 8046817 + * @summary schemagen fails to generate xsd for enum types + * @run main/othervm GenerateEnumSchema + */ +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Paths; +import java.util.Scanner; + +public class GenerateEnumSchema { + + private static final String SCHEMA_OUTPUT_FILENAME = "schema1.xsd"; + private static final File schemaOutputFile = new File(SCHEMA_OUTPUT_FILENAME); + + public static void main(String[] args) throws Exception, IOException { + //Check schema generation for class type + runSchemaGen("TestClassType.java"); + checkIfSchemaGenerated(); + checkSchemaContent("<xs:complexType name=\"testClassType\">"); + checkSchemaContent("<xs:element name=\"a\" type=\"xs:int\"/>"); + schemaOutputFile.delete(); + //Check schema generation for enum type + runSchemaGen("TestEnumType.java"); + checkIfSchemaGenerated(); + checkSchemaContent("<xs:simpleType name=\"testEnumType\">"); + checkSchemaContent("<xs:enumeration value=\"ONE\"/>"); + checkSchemaContent("<xs:enumeration value=\"TWO\"/>"); + checkSchemaContent("<xs:enumeration value=\"THREE\"/>"); + schemaOutputFile.delete(); + } + + private static void checkIfSchemaGenerated() { + if (!schemaOutputFile.exists()) { + throw new RuntimeException("FAIL:" + SCHEMA_OUTPUT_FILENAME + " was not generated by schemagen tool"); + } + } + + private static void checkSchemaContent(String exp_token) throws FileNotFoundException { + System.out.print("Check if generated schema contains '" + exp_token + "' string: "); + try (Scanner scanner = new Scanner(schemaOutputFile)) { + if (scanner.findWithinHorizon(exp_token, 0) != null) { + System.out.println("OK"); + return; + } + } + System.out.println("FAIL"); + throw new RuntimeException("The '" + exp_token + "' is not found in generated schema"); + + } + + private static String getClassFilePath(String filename) { + String testSrc = System.getProperty("test.src"); + if (testSrc == null) { + testSrc = "."; + } + return Paths.get(testSrc).resolve(filename).toString(); + } + + private static String getSchemagen() { + String javaHome = System.getProperty("java.home"); + if (javaHome.endsWith("jre")) { + javaHome = new File(javaHome).getParent(); + } + String schemagen = javaHome + File.separator + "bin" + File.separator + "schemagen"; + if (System.getProperty("os.name").startsWith("Windows")) { + schemagen = schemagen.concat(".exe"); + } + return schemagen; + } + + private static void logOutput(Process p) throws IOException { + BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); + String s = r.readLine(); + while (s != null) { + System.out.println(s.trim()); + s = r.readLine(); + } + } + + private static void runSchemaGen(String classFile) { + String schemagen = getSchemagen(); + + try { + System.out.println("Call to schemagen: " + schemagen + " " + classFile); + String[] schemagen_args = { + schemagen, + getClassFilePath(classFile) + }; + + ProcessBuilder pb = new ProcessBuilder(schemagen_args); + pb.redirectErrorStream(true); + Process p = pb.start(); + logOutput(p); + int result = p.waitFor(); + p.destroy(); + + if (result != 0) { + throw new RuntimeException("schemagen failed"); + } + } catch (IOException | InterruptedException e) { + System.err.println("Can't run schemagen tool. Exception:"); + e.printStackTrace(System.err); + throw new RuntimeException("Error launching schemagen tool"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/ws/8046817/TestClassType.java Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +import javax.xml.bind.annotation.XmlType; + +@XmlType +public class TestClassType { + public int a; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/ws/8046817/TestEnumType.java Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +import javax.xml.bind.annotation.XmlEnum; + +@XmlEnum(String.class) +public enum TestEnumType { + ONE, TWO, THREE +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JarUtils.java Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015, 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. + * + * 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. + */ + +package jdk.testlibrary; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +/** + * Common library for various test jar file utility functions. + */ +public final class JarUtils { + + /** + * Create jar file with specified files. + */ + public static void createJar(String dest, String... files) + throws IOException { + try (JarOutputStream jos = new JarOutputStream( + new FileOutputStream(dest), new Manifest())) { + for (String file : files) { + System.out.println(String.format("Adding %s to %s", + file, dest)); + + // add an archive entry, and write a file + jos.putNextEntry(new JarEntry(file)); + try (FileInputStream fis = new FileInputStream(file)) { + fis.transferTo(jos); + } + } + } + System.out.println(); + } + + /** + * Add specified files to existing jar file. + */ + public static void updateJar(String src, String dest, String... files) + throws IOException { + try (JarOutputStream jos = new JarOutputStream( + new FileOutputStream(dest))) { + + // copy each old entry into destination unless the entry name + // is in the updated list + List<String> updatedFiles = new ArrayList<>(); + try (JarFile srcJarFile = new JarFile(src)) { + Enumeration entries = srcJarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = (JarEntry) entries.nextElement(); + String name = entry.getName(); + boolean found = false; + for (String file : files) { + if (name.equals(file)) { + updatedFiles.add(file); + found = true; + break; + } + } + + if (found) { + System.out.println(String.format("Updating %s with %s", + dest, name)); + jos.putNextEntry(new JarEntry(name)); + try (FileInputStream fis = new FileInputStream(name)) { + fis.transferTo(jos); + } + } else { + System.out.println(String.format("Copying %s to %s", + name, dest)); + jos.putNextEntry(entry); + srcJarFile.getInputStream(entry).transferTo(jos); + } + } + } + + // append new files + for (String file : files) { + if (!updatedFiles.contains(file)) { + System.out.println(String.format("Adding %s with %s", + dest, file)); + jos.putNextEntry(new JarEntry(file)); + try (FileInputStream fis = new FileInputStream(file)) { + fis.transferTo(jos); + } + } + } + } + System.out.println(); + } + +}
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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,6 +30,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.concurrent.CountDownLatch; import java.util.Map; @@ -378,4 +379,40 @@ } return cmd.toString().trim(); } + + /** + * Executes a process, waits for it to finish, prints the process output + * to stdout, and returns the process output. + * + * The process will have exited before this method returns. + * + * @param cmds The command line to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeCommand(String... cmds) + throws Throwable { + String cmdLine = Arrays.stream(cmds).collect(Collectors.joining(" ")); + System.out.println("Command line: [" + cmdLine + "]"); + OutputAnalyzer analyzer = ProcessTools.executeProcess(cmds); + System.out.println(analyzer.getOutput()); + return analyzer; + } + + /** + * Executes a process, waits for it to finish, prints the process output + * to stdout and returns the process output. + * + * The process will have exited before this method returns. + * + * @param pb The ProcessBuilder to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeCommand(ProcessBuilder pb) + throws Throwable { + String cmdLine = pb.command().stream().collect(Collectors.joining(" ")); + System.out.println("Command line: [" + cmdLine + "]"); + OutputAnalyzer analyzer = ProcessTools.executeProcess(pb); + System.out.println(analyzer.getOutput()); + return analyzer; + } }
--- a/jdk/test/sun/security/krb5/auto/Context.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/sun/security/krb5/auto/Context.java Thu Jan 29 15:35:29 2015 -0800 @@ -23,6 +23,7 @@ import com.sun.security.auth.module.Krb5LoginModule; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -584,7 +585,12 @@ out.name = name + " as " + out.cred.getName().toString(); return out; } catch (PrivilegedActionException pae) { - throw pae.getException(); + Exception e = pae.getException(); + if (e instanceof InvocationTargetException) { + throw (Exception)((InvocationTargetException) e).getTargetException(); + } else { + throw e; + } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/krb5/auto/ForwardableCheck.java Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +/* + * @test + * @bug 8022582 + * @summary Relax response flags checking in sun.security.krb5.KrbKdcRep.check. + * @compile -XDignore.symbol.file ForwardableCheck.java + * @run main/othervm ForwardableCheck + */ + +import org.ietf.jgss.GSSException; +import sun.security.jgss.GSSUtil; + +import java.util.Arrays; + +public class ForwardableCheck { + + public static void main(String[] args) throws Exception { + OneKDC kdc = new OneKDC(null); + kdc.writeJAASConf(); + + // USER can impersonate someone else + kdc.setOption(KDC.Option.ALLOW_S4U2SELF, + Arrays.asList(OneKDC.USER + "@" + OneKDC.REALM)); + // USER2 is sensitive + kdc.setOption(KDC.Option.SENSITIVE_ACCOUNTS, + Arrays.asList(OneKDC.USER2 + "@" + OneKDC.REALM)); + + Context c; + + // USER2 is sensitive but it's still able to get a normal ticket + c = Context.fromUserPass(OneKDC.USER2, OneKDC.PASS2, false); + + // ... and connect to another account + c.startAsClient(OneKDC.USER, GSSUtil.GSS_KRB5_MECH_OID); + c.x().requestCredDeleg(true); + c.x().requestMutualAuth(false); + + c.take(new byte[0]); + + if (!c.x().isEstablished()) { + throw new Exception("Context should have been established"); + } + + // ... but will not be able to delegate itself + if (c.x().getCredDelegState()) { + throw new Exception("Impossible"); + } + + // Although USER is allowed to impersonate other people, + // it cannot impersonate USER2 coz it's sensitive. + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + try { + c.impersonate(OneKDC.USER2); + throw new Exception("Should fail"); + } catch (GSSException e) { + e.printStackTrace(); + } + } +}
--- a/jdk/test/sun/security/krb5/auto/KDC.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/sun/security/krb5/auto/KDC.java Thu Jan 29 15:35:29 2015 -0800 @@ -198,6 +198,10 @@ * Krb5.KDC_ERR_POLICY will be send for S4U2proxy request. */ ALLOW_S4U2PROXY, + /** + * Sensitive accounts can never be delegated. + */ + SENSITIVE_ACCOUNTS, }; static { @@ -643,7 +647,7 @@ try { System.out.println(realm + "> " + tgsReq.reqBody.cname + " sends TGS-REQ for " + - service); + service + ", " + tgsReq.reqBody.kdcOptions); KDCReqBody body = tgsReq.reqBody; int[] eTypes = KDCReqBodyDotEType(body); int e2 = eTypes[0]; // etype for outgoing session key @@ -719,7 +723,13 @@ boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; if (body.kdcOptions.get(KDCOptions.FORWARDABLE) && allowForwardable) { - bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + List<String> sensitives = (List<String>) + options.get(Option.SENSITIVE_ACCOUNTS); + if (sensitives != null && sensitives.contains(cname.toString())) { + // Cannot make FORWARDABLE + } else { + bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + } } if (body.kdcOptions.get(KDCOptions.FORWARDED) || etp.flags.get(Krb5.TKT_OPTS_FORWARDED)) { @@ -824,7 +834,8 @@ t, edata); System.out.println(" Return " + tgsRep.cname - + " ticket for " + tgsRep.ticket.sname); + + " ticket for " + tgsRep.ticket.sname + ", flags " + + tFlags); DerOutputStream out = new DerOutputStream(); out.write(DerValue.createTag(DerValue.TAG_APPLICATION, @@ -869,7 +880,7 @@ try { System.out.println(realm + "> " + asReq.reqBody.cname + " sends AS-REQ for " + - service); + service + ", " + asReq.reqBody.kdcOptions); KDCReqBody body = asReq.reqBody; @@ -926,7 +937,13 @@ //body.from boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; if (body.kdcOptions.get(KDCOptions.FORWARDABLE)) { - bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + List<String> sensitives = (List<String>) + options.get(Option.SENSITIVE_ACCOUNTS); + if (sensitives != null && sensitives.contains(body.cname.toString())) { + // Cannot make FORWARDABLE + } else { + bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + } } if (body.kdcOptions.get(KDCOptions.RENEWABLE)) { bFlags[Krb5.TKT_OPTS_RENEWABLE] = true; @@ -1102,7 +1119,8 @@ edata); System.out.println(" Return " + asRep.cname - + " ticket for " + asRep.ticket.sname); + + " ticket for " + asRep.ticket.sname + ", flags " + + tFlags); DerOutputStream out = new DerOutputStream(); out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
--- a/jdk/test/sun/security/krb5/config/ParseConfig.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/sun/security/krb5/config/ParseConfig.java Thu Jan 29 15:35:29 2015 -0800 @@ -22,7 +22,7 @@ */ /* * @test - * @bug 6319046 + * @bug 6319046 8055045 * @compile -XDignore.symbol.file ParseConfig.java * @run main/othervm ParseConfig * @summary Problem with parsing krb5.conf @@ -32,7 +32,8 @@ public class ParseConfig { public static void main(String[] args) throws Exception { - System.setProperty("java.security.krb5.conf", System.getProperty("test.src", ".") +"/krb5.conf"); + System.setProperty("java.security.krb5.conf", + System.getProperty("test.src", ".") + "/krb5.conf"); Config config = Config.getInstance(); config.listTable(); @@ -44,5 +45,11 @@ expected + "\""); } } + + // JDK-8055045: IOOBE when reading an empty value + config.get("empty1", "NOVAL.COM"); + config.get("empty2", "NOVAL.COM"); + config.get("quote1", "NOVAL.COM"); + config.get("quote2", "NOVAL.COM"); } }
--- a/jdk/test/sun/security/krb5/config/krb5.conf Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/sun/security/krb5/config/krb5.conf Thu Jan 29 15:35:29 2015 -0800 @@ -27,3 +27,9 @@ } } + NOVAL.COM = { + empty1 = + empty2 =. + quote1 = " + quote2 = ' + }
--- a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java Wed Jan 28 16:45:45 2015 -0800 +++ b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java Thu Jan 29 15:35:29 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -58,7 +58,12 @@ static final String defaultPolicyId = "2.3.4.5"; - static class Handler implements HttpHandler { + static class Handler implements HttpHandler, AutoCloseable { + + private final HttpServer httpServer; + private final String keystore; + + @Override public void handle(HttpExchange t) throws IOException { int len = 0; for (String h: t.getRequestHeaders().keySet()) { @@ -136,7 +141,9 @@ // Write TSResponse System.err.println("\nResponse\n==================="); KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(new FileInputStream(TSKS), "changeit".toCharArray()); + try (FileInputStream fis = new FileInputStream(keystore)) { + ks.load(fis, "changeit".toCharArray()); + } String alias = "ts"; if (path == 6) alias = "tsbad1"; @@ -240,33 +247,74 @@ return out.toByteArray(); } + + private Handler(HttpServer httpServer, String keystore) { + this.httpServer = httpServer; + this.keystore = keystore; + } + + /** + * Initialize TSA instance. + * + * Extended Key Info extension of certificate that is used for + * signing TSA responses should contain timeStamping value. + */ + static Handler init(int port, String keystore) throws IOException { + HttpServer httpServer = HttpServer.create( + new InetSocketAddress(port), 0); + Handler tsa = new Handler(httpServer, keystore); + httpServer.createContext("/", tsa); + return tsa; + } + + /** + * Start TSA service. + */ + void start() { + httpServer.start(); + } + + /** + * Stop TSA service. + */ + void stop() { + httpServer.stop(0); + } + + /** + * Return server port number. + */ + int getPort() { + return httpServer.getAddress().getPort(); + } + + @Override + public void close() throws Exception { + stop(); + } } public static void main(String[] args) throws Exception { + try (Handler tsa = Handler.init(0, TSKS);) { + tsa.start(); + int port = tsa.getPort(); - Handler h = new Handler(); - HttpServer server = HttpServer.create(new InetSocketAddress(0), 0); - int port = server.getAddress().getPort(); - HttpContext ctx = server.createContext("/", h); - server.start(); + String cmd; + // Use -J-Djava.security.egd=file:/dev/./urandom to speed up + // nonce generation in timestamping request. Not avaibale on + // Windows and defaults to thread seed generator, not too bad. + if (System.getProperty("java.home").endsWith("jre")) { + cmd = System.getProperty("java.home") + "/../bin/jarsigner"; + } else { + cmd = System.getProperty("java.home") + "/bin/jarsigner"; + } - String cmd = null; - // Use -J-Djava.security.egd=file:/dev/./urandom to speed up - // nonce generation in timestamping request. Not avaibale on - // Windows and defaults to thread seed generator, not too bad. - if (System.getProperty("java.home").endsWith("jre")) { - cmd = System.getProperty("java.home") + "/../bin/jarsigner"; - } else { - cmd = System.getProperty("java.home") + "/bin/jarsigner"; - } + cmd += " " + System.getProperty("test.tool.vm.opts") + + " -J-Djava.security.egd=file:/dev/./urandom" + + " -debug -keystore " + TSKS + " -storepass changeit" + + " -tsa http://localhost:" + port + "/%d" + + " -signedjar new_%d.jar " + JAR + " old"; - cmd += " " + System.getProperty("test.tool.vm.opts") + - " -J-Djava.security.egd=file:/dev/./urandom" + - " -debug -keystore " + TSKS + " -storepass changeit" + - " -tsa http://localhost:" + port + "/%d" + - " -signedjar new_%d.jar " + JAR + " old"; - - try { if (args.length == 0) { // Run this test jarsigner(cmd, 0, true); // Success, normal call jarsigner(cmd, 1, false); // These 4 should fail @@ -287,8 +335,6 @@ System.err.println("Press Enter to quit server"); System.in.read(); } - } finally { - server.stop(0); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/jarsigner/TsacertOptionTest.java Thu Jan 29 15:35:29 2015 -0800 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2013, 2015, 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. + * + * 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. + */ + +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; +import jdk.testlibrary.JarUtils; + +/** + * @test + * @bug 8024302 8026037 + * @summary The test signs and verifies a jar file with -tsacert option + * @library /lib/testlibrary + * @run main TsacertOptionTest + */ +public class TsacertOptionTest { + + private static final String FS = System.getProperty("file.separator"); + private static final String JAVA_HOME = System.getProperty("java.home"); + private static final String KEYTOOL = JAVA_HOME + FS + "bin" + FS + + "keytool"; + private static final String JARSIGNER = JAVA_HOME + FS + "bin" + FS + + "jarsigner"; + private static final String UNSIGNED_JARFILE = "unsigned.jar"; + private static final String SIGNED_JARFILE = "signed.jar"; + private static final String FILENAME = TsacertOptionTest.class.getName() + + ".txt"; + private static final String PASSWORD = "changeit"; + private static final String KEYSTORE = "ks.jks"; + private static final String SIGNING_KEY_ALIAS = "sign_alias"; + private static final String TSA_KEY_ALIAS = "ts"; + private static final String KEY_ALG = "RSA"; + private static final int KEY_SIZE = 2048; + private static final int VALIDITY = 365; + private static final String WARNING = "Warning:"; + private static final String JAR_SIGNED = "jar signed."; + private static final String JAR_VERIFIED = "jar verified."; + + /** + * The test signs and verifies a jar file with -tsacert option, + * and checks that no warning was shown. + * A certificate that is addressed in -tsacert option contains URL to TSA + * in Subject Information Access extension. + */ + public static void main(String[] args) throws Throwable { + TsacertOptionTest test = new TsacertOptionTest(); + test.start(); + }