diff --git a/jdk/.hgtags b/jdk/.hgtags index 8c3ca49faa6..29decea481b 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -49,3 +49,4 @@ b3f3240135f0c10b9f2481c174b81b7fcf0daa60 jdk7-b71 460639b036f327282832a4fe52b7aa45688afd50 jdk7-b72 f708138c9aca4b389872838fe6773872fce3609e jdk7-b73 eacb36e30327e7ae33baa068e82ddccbd91eaae2 jdk7-b74 +8885b22565077236a927e824ef450742e434a230 jdk7-b75 diff --git a/jdk/make/common/Defs-linux.gmk b/jdk/make/common/Defs-linux.gmk index 5cd9d9222f8..f1efcefd0a6 100644 --- a/jdk/make/common/Defs-linux.gmk +++ b/jdk/make/common/Defs-linux.gmk @@ -116,8 +116,16 @@ CFLAGS_REQUIRED_sparcv9 += -m64 -mcpu=v9 LDFLAGS_COMMON_sparcv9 += -m64 -mcpu=v9 CFLAGS_REQUIRED_sparc += -m32 -mcpu=v9 LDFLAGS_COMMON_sparc += -m32 -mcpu=v9 -CFLAGS_REQUIRED = $(CFLAGS_REQUIRED_$(ARCH)) -LDFLAGS_COMMON += $(LDFLAGS_COMMON_$(ARCH)) +ifeq ($(ZERO_BUILD), true) + CFLAGS_REQUIRED = $(ZERO_ARCHFLAG) + ifeq ($(ZERO_ENDIANNESS), little) + CFLAGS_REQUIRED += -D_LITTLE_ENDIAN + endif + LDFLAGS_COMMON += $(ZERO_ARCHFLAG) +else + CFLAGS_REQUIRED = $(CFLAGS_REQUIRED_$(ARCH)) + LDFLAGS_COMMON += $(LDFLAGS_COMMON_$(ARCH)) +endif # If this is a --hash-style=gnu system, use --hash-style=both # The gnu .hash section won't work on some Linux systems like SuSE 10. @@ -217,7 +225,7 @@ endif EXTRA_LIBS += -lc -LDFLAGS_DEFS_OPTION = -z defs +LDFLAGS_DEFS_OPTION = -Xlinker -z -Xlinker defs LDFLAGS_COMMON += $(LDFLAGS_DEFS_OPTION) # diff --git a/jdk/make/common/Defs.gmk b/jdk/make/common/Defs.gmk index 6e9695b8ad7..de974fe62ec 100644 --- a/jdk/make/common/Defs.gmk +++ b/jdk/make/common/Defs.gmk @@ -667,12 +667,7 @@ LDLIBS = $(OTHER_LDLIBS) $(LDLIBS_$(VARIANT)) $(LDLIBS_COMMON) LINTFLAGS = $(LINTFLAGS_$(VARIANT)) $(LINTFLAGS_COMMON) \ $(OTHER_LINTFLAGS) -# this should be moved into Defs-.gmk..... -ifeq ($(PLATFORM), windows) - VERSION_DEFINES = -DRELEASE="\"$(RELEASE)\"" -else - VERSION_DEFINES = -DRELEASE='"$(RELEASE)"' -endif +VERSION_DEFINES = -DRELEASE='"$(RELEASE)"' # Note: As a rule, GNU Make rules should not appear in any of the # Defs*.gmk files. These were added for Kestrel-Solaris and do address diff --git a/jdk/make/common/Program.gmk b/jdk/make/common/Program.gmk index 067ffa39b9e..091ec95f809 100644 --- a/jdk/make/common/Program.gmk +++ b/jdk/make/common/Program.gmk @@ -85,7 +85,7 @@ ifneq (,$(findstring $(PLATFORM), linux solaris)) # UNIX systems endif endif ifeq ($(PLATFORM), linux) - LDFLAGS += -z origin + LDFLAGS += -Wl,-z -Wl,origin LDFLAGS += -Wl,--allow-shlib-undefined LDFLAGS += -Wl,-rpath -Wl,\$$ORIGIN/../lib/$(LIBARCH)/jli LDFLAGS += -Wl,-rpath -Wl,\$$ORIGIN/../jre/lib/$(LIBARCH)/jli @@ -236,13 +236,13 @@ endif # files endif # INCREMENTAL_BUILD ifdef JAVA_ARGS -OTHER_CPPFLAGS += -DJAVA_ARGS=$(JAVA_ARGS) -OTHER_CPPFLAGS += -DLAUNCHER_NAME=\"$(LAUNCHER_NAME)\" +OTHER_CPPFLAGS += -DJAVA_ARGS='$(JAVA_ARGS)' +OTHER_CPPFLAGS += -DLAUNCHER_NAME='"$(LAUNCHER_NAME)"' endif ifeq ($(PLATFORM), windows) ifdef RELEASE -OTHER_CPPFLAGS += -DVERSION="$(RELEASE)" +OTHER_CPPFLAGS += -DVERSION='"$(RELEASE)"' endif endif @@ -258,14 +258,8 @@ endif OTHER_INCLUDES += -I$(LAUNCHER_SHARE_SRC)/bin -I$(LAUNCHER_PLATFORM_SRC)/bin OTHER_INCLUDES += -I$(SHARE_SRC)/native/java/util/zip/zlib-1.1.3 -# this may not be necessary... -ifeq ($(PLATFORM), windows) -OTHER_CPPFLAGS += -DPROGNAME="\"$(PROGRAM)\"" -VERSION_DEFINES += -DFULL_VERSION="\"$(FULL_VERSION)\"" -else OTHER_CPPFLAGS += -DPROGNAME='"$(PROGRAM)"' VERSION_DEFINES += -DFULL_VERSION='"$(FULL_VERSION)"' -endif VERSION_DEFINES += -DJDK_MAJOR_VERSION='"$(JDK_MAJOR_VERSION)"' \ -DJDK_MINOR_VERSION='"$(JDK_MINOR_VERSION)"' @@ -279,8 +273,14 @@ $(OBJDIR)/main.$(OBJECT_SUFFIX): $(LAUNCHER_SHARE_SRC)/bin/main.c # # How to install jvm.cfg. -# -$(JVMCFG): $(LAUNCHER_PLATFORM_SRC)/bin/$(ARCH)/jvm.cfg +# +ifeq ($(ZERO_BUILD), true) +JVMCFG_ARCH = zero +else +JVMCFG_ARCH = $(ARCH) +endif + +$(JVMCFG): $(LAUNCHER_PLATFORM_SRC)/bin/$(JVMCFG_ARCH)/jvm.cfg $(install-file) # diff --git a/jdk/make/common/Release.gmk b/jdk/make/common/Release.gmk index 93244dcc47f..eb1335eef22 100644 --- a/jdk/make/common/Release.gmk +++ b/jdk/make/common/Release.gmk @@ -330,7 +330,7 @@ endif # # Specific files and directories that will be filtered out from above areas. # -SOURCE_FILTERs = $(SCM_DIRs) 'X-*' '*-X-*' '*-template.java' ',*' +SOURCE_FILTERs = $(SCM_DIRs) ',*' SOURCE_FILES_filter = $(SOURCE_FILTERs:%=-name % -prune -o) # diff --git a/jdk/make/common/Rules.gmk b/jdk/make/common/Rules.gmk index 251b31f53a2..daa8dd93037 100644 --- a/jdk/make/common/Rules.gmk +++ b/jdk/make/common/Rules.gmk @@ -63,7 +63,7 @@ endif # If AUTO_FILES_PROPERTIES_DIRS used, automatically find properties files # ifdef AUTO_FILES_PROPERTIES_DIRS - AUTO_FILES_PROPERTIES_FILTERS1 = $(SCM_DIRs) 'X-*' '*-X-*' ',*' + AUTO_FILES_PROPERTIES_FILTERS1 = $(SCM_DIRs) ',*' AUTO_FILES_PROPERTIES_FILTERS1 += $(AUTO_PROPERTIES_PRUNE) FILES_properties_find_filters1 = $(AUTO_FILES_PROPERTIES_FILTERS1:%=-name % -prune -o) FILES_properties_auto1 := \ @@ -111,7 +111,7 @@ include $(JDK_TOPDIR)/make/common/internal/Resources.gmk ifdef AUTO_FILES_JAVA_DIRS # Filter out these files or directories - AUTO_FILES_JAVA_SOURCE_FILTERS1 = $(SCM_DIRs) 'X-*' '*-X-*' '*-template.java' ',*' + AUTO_FILES_JAVA_SOURCE_FILTERS1 = $(SCM_DIRs) ',*' AUTO_FILES_JAVA_SOURCE_FILTERS2 = AUTO_FILES_JAVA_SOURCE_FILTERS1 += $(AUTO_JAVA_PRUNE) AUTO_FILES_JAVA_SOURCE_FILTERS2 += $(AUTO_JAVA_PRUNE) diff --git a/jdk/make/java/instrument/Makefile b/jdk/make/java/instrument/Makefile index 646fcdc6f34..f46b3d10cc1 100644 --- a/jdk/make/java/instrument/Makefile +++ b/jdk/make/java/instrument/Makefile @@ -109,7 +109,7 @@ else LDFLAGS += -R \$$ORIGIN/jli endif ifeq ($(PLATFORM), linux) - LDFLAGS += -z origin + LDFLAGS += -Wl,-z -Wl,origin LDFLAGS += -Wl,--allow-shlib-undefined LDFLAGS += -Wl,-rpath -Wl,\$$ORIGIN/jli endif diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index a6ab86058f7..3acda4705d0 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -287,11 +287,18 @@ JAVA_JAVA_java = \ java/util/concurrent/ExecutorService.java \ java/util/concurrent/ExecutorCompletionService.java \ java/util/concurrent/Executors.java \ + java/util/concurrent/ForkJoinPool.java \ + java/util/concurrent/ForkJoinTask.java \ + java/util/concurrent/ForkJoinWorkerThread.java \ java/util/concurrent/Future.java \ java/util/concurrent/FutureTask.java \ java/util/concurrent/LinkedBlockingDeque.java \ java/util/concurrent/LinkedBlockingQueue.java \ + java/util/concurrent/LinkedTransferQueue.java \ + java/util/concurrent/Phaser.java \ java/util/concurrent/PriorityBlockingQueue.java \ + java/util/concurrent/RecursiveAction.java \ + java/util/concurrent/RecursiveTask.java \ java/util/concurrent/RejectedExecutionException.java \ java/util/concurrent/RejectedExecutionHandler.java \ java/util/concurrent/RunnableFuture.java \ @@ -302,9 +309,11 @@ JAVA_JAVA_java = \ java/util/concurrent/Semaphore.java \ java/util/concurrent/SynchronousQueue.java \ java/util/concurrent/ThreadFactory.java \ + java/util/concurrent/ThreadLocalRandom.java \ java/util/concurrent/ThreadPoolExecutor.java \ java/util/concurrent/TimeUnit.java \ java/util/concurrent/TimeoutException.java \ + java/util/concurrent/TransferQueue.java \ java/util/concurrent/atomic/AtomicBoolean.java \ java/util/concurrent/atomic/AtomicInteger.java \ java/util/concurrent/atomic/AtomicIntegerArray.java \ diff --git a/jdk/make/java/jli/Makefile b/jdk/make/java/jli/Makefile index 7f972f16031..861d5375e92 100644 --- a/jdk/make/java/jli/Makefile +++ b/jdk/make/java/jli/Makefile @@ -48,11 +48,15 @@ ZIP_SRC = $(SHARE_SRC)/native/java/util/zip/zlib-$(ZLIB_VERSION) LAUNCHER_SHARE_SRC = $(SHARE_SRC)/bin LAUNCHER_PLATFORM_SRC = $(PLATFORM_SRC)/bin +ifeq ($(ZERO_BUILD), true) +ERGO_FAMILY=zero +else ifeq ($(ARCH_FAMILY), amd64) ERGO_FAMILY=i586 else ERGO_FAMILY=$(ARCH_FAMILY) endif +endif # diff --git a/jdk/make/java/main/java/Makefile b/jdk/make/java/main/java/Makefile index b4cf42f648f..ae9ce618cdd 100644 --- a/jdk/make/java/main/java/Makefile +++ b/jdk/make/java/main/java/Makefile @@ -57,7 +57,7 @@ endif # include $(BUILDDIR)/common/Program.gmk OTHER_CPPFLAGS += -DEXPAND_CLASSPATH_WILDCARDS -OTHER_CPPFLAGS += -DLAUNCHER_NAME=\"$(LAUNCHER_NAME)\" +OTHER_CPPFLAGS += -DLAUNCHER_NAME='"$(LAUNCHER_NAME)"' ifeq ($(PLATFORM), solaris) LDFLAGS += -R$(OPENWIN_LIB) diff --git a/jdk/make/java/main/javaw/Makefile b/jdk/make/java/main/javaw/Makefile index fb4479afad3..7ebc218f669 100644 --- a/jdk/make/java/main/javaw/Makefile +++ b/jdk/make/java/main/javaw/Makefile @@ -62,4 +62,5 @@ endif # include $(BUILDDIR)/common/Program.gmk OTHER_CPPFLAGS += -DEXPAND_CLASSPATH_WILDCARDS -OTHER_CPPFLAGS += -DLAUNCHER_NAME=\"$(LAUNCHER_NAME)\" +OTHER_CPPFLAGS += -DLAUNCHER_NAME='"$(LAUNCHER_NAME)"' + diff --git a/jdk/make/java/nio/Makefile b/jdk/make/java/nio/Makefile index b792d3f86a3..e0cb40839e8 100644 --- a/jdk/make/java/nio/Makefile +++ b/jdk/make/java/nio/Makefile @@ -335,6 +335,15 @@ SCH_SRC=$(SNIO_SRC)/ch SCS_SRC=$(SNIO_SRC)/cs SFS_SRC=$(SNIO_SRC)/fs +# Template files +HEAP_X_BUF_TEMPLATE=$(BUF_SRC)/Heap-X-Buffer.java.template +BYTE_X_BUF_TEMPLATE=$(BUF_SRC)/ByteBufferAs-X-Buffer.java.template +X_BUF_TEMPLATE=$(BUF_SRC)/X-Buffer.java.template +X_BUF_BIN_TEMPLATE=$(BUF_SRC)/X-Buffer-bin.java.template +DIRECT_X_BUF_TEMPLATE=$(BUF_SRC)/Direct-X-Buffer.java.template +DIRECT_X_BUF_BIN_TEMPLATE=$(BUF_SRC)/Direct-X-Buffer-bin.java.template +CHARSET_X_CODER_TEMPLATE=$(CS_SRC)/Charset-X-Coder.java.template + BUF_GEN=$(NIO_GEN) CH_GEN=$(NIO_GEN)/channels CS_GEN=$(NIO_GEN)/charset @@ -357,39 +366,39 @@ GEN_BUFFER_CMD = SPP="$(SPP_CMD)" NAWK="$(NAWK)" SED="$(SED)" SH="$(SH)" \ # Public abstract buffer classes # -$(BUF_GEN)/ByteBuffer.java: $(BUF_SRC)/X-Buffer.java \ - $(BUF_SRC)/X-Buffer-bin.java \ +$(BUF_GEN)/ByteBuffer.java: $(X_BUF_TEMPLATE) \ + $(X_BUF_BIN_TEMPLATE) \ $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=byte BIN=1 SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/CharBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/CharBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ShortBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ShortBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/IntBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/IntBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/LongBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/LongBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/FloatBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/FloatBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DoubleBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DoubleBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -397,72 +406,72 @@ $(BUF_GEN)/DoubleBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) # Buffers whose contents are heap-allocated # -$(BUF_GEN)/HeapByteBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapByteBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=byte SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapByteBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapByteBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=byte RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapCharBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapCharBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapCharBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapCharBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapShortBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapShortBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapShortBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapShortBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapIntBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapIntBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapIntBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapIntBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapLongBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapLongBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapLongBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapLongBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapFloatBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapFloatBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapFloatBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapFloatBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapDoubleBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapDoubleBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapDoubleBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapDoubleBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -470,15 +479,15 @@ $(BUF_GEN)/HeapDoubleBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH # Direct byte buffer # -$(BUF_GEN)/DirectByteBuffer.java: $(BUF_SRC)/Direct-X-Buffer.java \ - $(BUF_SRC)/Direct-X-Buffer.java \ +$(BUF_GEN)/DirectByteBuffer.java: $(DIRECT_X_BUF_TEMPLATE) \ + $(DIRECT_X_BUF_TEMPLATE) \ $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=byte BIN=1 SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectByteBuffer%.java: $(BUF_SRC)/Direct-X-Buffer.java \ - $(BUF_SRC)/Direct-X-Buffer.java \ +$(BUF_GEN)/DirectByteBuffer%.java: $(DIRECT_X_BUF_TEMPLATE) \ + $(DIRECT_X_BUF_TEMPLATE) \ $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp @@ -487,62 +496,62 @@ $(BUF_GEN)/DirectByteBuffer%.java: $(BUF_SRC)/Direct-X-Buffer.java \ # Unswapped views of direct byte buffers # -$(BUF_GEN)/DirectCharBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectCharBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectCharBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectCharBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectShortBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectShortBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectShortBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectShortBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectIntBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectIntBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectIntBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectIntBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectLongBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectLongBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectLongBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectLongBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectFloatBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectFloatBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectFloatBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectFloatBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectDoubleBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectDoubleBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectDoubleBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectDoubleBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -550,62 +559,62 @@ $(BUF_GEN)/DirectDoubleBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFF # Swapped views of direct byte buffers # -$(BUF_GEN)/DirectCharBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectCharBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectCharBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectCharBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectShortBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectShortBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectShortBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectShortBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectIntBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectIntBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectIntBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectIntBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectLongBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectLongBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectLongBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectLongBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectFloatBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectFloatBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectFloatBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectFloatBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectDoubleBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectDoubleBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectDoubleBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectDoubleBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -613,62 +622,62 @@ $(BUF_GEN)/DirectDoubleBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFF # Big-endian views of byte buffers # -$(BUF_GEN)/ByteBufferAsCharBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsCharBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsCharBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsCharBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsShortBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsShortBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsShortBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsShortBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsIntBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsIntBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsIntBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsIntBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsLongBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsLongBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsLongBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsLongBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsFloatBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsFloatBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsFloatBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsFloatBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsDoubleBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsDoubleBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsDoubleBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsDoubleBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -676,62 +685,62 @@ $(BUF_GEN)/ByteBufferAsDoubleBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.jav # Little-endian views of byte buffers # -$(BUF_GEN)/ByteBufferAsCharBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsCharBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsCharBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsCharBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsShortBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsShortBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsShortBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsShortBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsIntBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsIntBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsIntBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsIntBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsLongBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsLongBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsLongBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsLongBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsFloatBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsFloatBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsFloatBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsFloatBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsDoubleBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsDoubleBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsDoubleBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsDoubleBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -745,13 +754,13 @@ GEN_CODER_SH = genCoder.sh GEN_CODER_CMD = SPP="$(SPP_CMD)" SED="$(SED)" NAWK="$(NAWK)" SH="$(SH)" $(SH) $(GEN_CODER_SH) -$(CS_GEN)/CharsetDecoder.java: $(CS_SRC)/Charset-X-Coder.java $(GEN_CODER_SH) +$(CS_GEN)/CharsetDecoder.java: $(CHARSET_X_CODER_TEMPLATE) $(GEN_CODER_SH) $(prep-target) @$(RM) $@.temp $(GEN_CODER_CMD) decoder $< $@.temp $(MV) $@.temp $@ -$(CS_GEN)/CharsetEncoder.java: $(CS_SRC)/Charset-X-Coder.java $(GEN_CODER_SH) +$(CS_GEN)/CharsetEncoder.java: $(CHARSET_X_CODER_TEMPLATE) $(GEN_CODER_SH) $(prep-target) @$(RM) $@.temp $(GEN_CODER_CMD) encoder $< $@.temp diff --git a/jdk/make/java/nio/genBuffer.sh b/jdk/make/java/nio/genBuffer.sh index ef10c125b1c..27e3f82f0fd 100644 --- a/jdk/make/java/nio/genBuffer.sh +++ b/jdk/make/java/nio/genBuffer.sh @@ -154,7 +154,7 @@ if [ $BIN ]; then mv $DST $DST.tmp sed -e '/#BIN/,$d' <$DST.tmp >$DST rm -f $DST.tmp - binops=`dirname $SRC`/`basename $SRC .java`-bin.java + binops=`dirname $SRC`/`basename $SRC .java.template`-bin.java.template genBinOps char character 1 two one $binops >>$DST genBinOps short short 1 two one $binops >>$DST genBinOps int integer 2 four three $binops >>$DST diff --git a/jdk/make/java/redist/Makefile b/jdk/make/java/redist/Makefile index 929504f55d1..b4ca64e5c14 100644 --- a/jdk/make/java/redist/Makefile +++ b/jdk/make/java/redist/Makefile @@ -94,11 +94,13 @@ ifeq ($(INCLUDE_SA), true) endif endif # INCLUDE_SA -# Hotspot client is only available on 32-bit builds +# Hotspot client is only available on 32-bit non-Zero builds +ifneq ($(ZERO_BUILD), true) ifeq ($(ARCH_DATA_MODEL), 32) IMPORT_LIST += $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(JVM_NAME) \ $(LIB_LOCATION)/$(CLIENT_LOCATION)/Xusage.txt endif +endif ifeq ($(PLATFORM), windows) # Windows vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Windows @@ -171,6 +173,7 @@ ifeq ($(PLATFORM), solaris) IMPORT_LIST += $(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVMDB_NAME) endif +ifneq ($(ZERO_BUILD), true) ifeq ($(ARCH_DATA_MODEL), 32) IMPORT_LIST += $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(LIBJSIG_NAME) @@ -201,6 +204,8 @@ endif # 32bit solaris endif # 32bit +endif # ZERO_BUILD + # NOT Windows ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NOT Windows endif # PLATFORM diff --git a/jdk/make/java/version/Makefile b/jdk/make/java/version/Makefile index ae4f60e7a49..448ac729e16 100644 --- a/jdk/make/java/version/Makefile +++ b/jdk/make/java/version/Makefile @@ -33,7 +33,7 @@ include $(BUILDDIR)/common/Defs.gmk all build: $(GENSRCDIR)/sun/misc/Version.java $(GENSRCDIR)/sun/misc/Version.java: \ - $(SHARE_SRC)/classes/sun/misc/Version-template.java + $(SHARE_SRC)/classes/sun/misc/Version.java.template $(prep-target) $(RM) $@.temp $(SED) -e 's/@@launcher_name@@/$(LAUNCHER_NAME)/g' \ diff --git a/jdk/make/javax/sound/Makefile b/jdk/make/javax/sound/Makefile index c3e0524fd46..5572e637b7c 100644 --- a/jdk/make/javax/sound/Makefile +++ b/jdk/make/javax/sound/Makefile @@ -128,7 +128,7 @@ endif # PLATFORM solaris # for dynamic inclusion of extra sound libs: these # JNI libs will be loaded from Platform.java -CPPFLAGS += -DEXTRA_SOUND_JNI_LIBS="\"$(EXTRA_SOUND_JNI_LIBS)\"" +CPPFLAGS += -DEXTRA_SOUND_JNI_LIBS='"$(EXTRA_SOUND_JNI_LIBS)"' # integrate MIDI i/o in jsound lib ifeq ($(INCLUDE_MIDI),TRUE) diff --git a/jdk/make/javax/sound/SoundDefs.gmk b/jdk/make/javax/sound/SoundDefs.gmk index 93dfdf46e6a..dd650010369 100644 --- a/jdk/make/javax/sound/SoundDefs.gmk +++ b/jdk/make/javax/sound/SoundDefs.gmk @@ -55,21 +55,25 @@ ifeq ($(PLATFORM), solaris) endif # PLATFORM solaris -ifeq ($(ARCH), i586) - CPPFLAGS += -DX_ARCH=X_I586 -endif # ARCH i586 +ifeq ($(ZERO_BUILD), true) + CPPFLAGS += -DX_ARCH=X_ZERO +else + ifeq ($(ARCH), i586) + CPPFLAGS += -DX_ARCH=X_I586 + endif # ARCH i586 -ifeq ($(ARCH), sparc) - CPPFLAGS += -DX_ARCH=X_SPARC -endif # ARCH sparc + ifeq ($(ARCH), sparc) + CPPFLAGS += -DX_ARCH=X_SPARC + endif # ARCH sparc -ifeq ($(ARCH), sparcv9) - CPPFLAGS += -DX_ARCH=X_SPARCV9 -endif # ARCH sparcv9 + ifeq ($(ARCH), sparcv9) + CPPFLAGS += -DX_ARCH=X_SPARCV9 + endif # ARCH sparcv9 -ifeq ($(ARCH), amd64) - CPPFLAGS += -DX_ARCH=X_AMD64 -endif # ARCH amd64 + ifeq ($(ARCH), amd64) + CPPFLAGS += -DX_ARCH=X_AMD64 + endif # ARCH amd64 +endif # files needed for MIDI i/o diff --git a/jdk/make/jdk_generic_profile.sh b/jdk/make/jdk_generic_profile.sh index 125198301ca..66d46bc287f 100644 --- a/jdk/make/jdk_generic_profile.sh +++ b/jdk/make/jdk_generic_profile.sh @@ -339,3 +339,82 @@ fi PATH="${path4sdk}" export PATH +# Export variables required for Zero +if [ "${ZERO_BUILD}" = true ] ; then + # ZERO_LIBARCH is the name of the architecture-specific + # subdirectory under $JAVA_HOME/jre/lib + arch=$(uname -m) + case "${arch}" in + x86_64) ZERO_LIBARCH=amd64 ;; + i?86) ZERO_LIBARCH=i386 ;; + sparc64) ZERO_LIBARCH=sparcv9 ;; + arm*) ZERO_LIBARCH=arm ;; + *) ZERO_LIBARCH="$(arch)" + esac + export ZERO_LIBARCH + + # ARCH_DATA_MODEL is the number of bits in a pointer + case "${ZERO_LIBARCH}" in + i386|ppc|s390|sparc|arm) + ARCH_DATA_MODEL=32 + ;; + amd64|ppc64|s390x|sparcv9|ia64|alpha) + ARCH_DATA_MODEL=64 + ;; + *) + echo "ERROR: Unable to determine ARCH_DATA_MODEL for ${ZERO_LIBARCH}" + exit 1 + esac + export ARCH_DATA_MODEL + + # ZERO_ENDIANNESS is the endianness of the processor + case "${ZERO_LIBARCH}" in + i386|amd64|ia64) + ZERO_ENDIANNESS=little + ;; + ppc*|s390*|sparc*|alpha) + ZERO_ENDIANNESS=big + ;; + *) + echo "ERROR: Unable to determine ZERO_ENDIANNESS for ${ZERO_LIBARCH}" + exit 1 + esac + export ZERO_ENDIANNESS + + # ZERO_ARCHDEF is used to enable architecture-specific code + case "${ZERO_LIBARCH}" in + i386) ZERO_ARCHDEF=IA32 ;; + ppc*) ZERO_ARCHDEF=PPC ;; + s390*) ZERO_ARCHDEF=S390 ;; + sparc*) ZERO_ARCHDEF=SPARC ;; + *) ZERO_ARCHDEF=$(echo "${ZERO_LIBARCH}" | tr a-z A-Z) + esac + export ZERO_ARCHDEF + + # ZERO_ARCHFLAG tells the compiler which mode to build for + case "${ZERO_LIBARCH}" in + s390) + ZERO_ARCHFLAG="-m31" + ;; + *) + ZERO_ARCHFLAG="-m${ARCH_DATA_MODEL}" + esac + export ZERO_ARCHFLAG + + # LIBFFI_CFLAGS and LIBFFI_LIBS tell the compiler how to compile and + # link against libffi + pkgconfig=$(which pkg-config 2>/dev/null) + if [ -x "${pkgconfig}" ] ; then + if [ "${LIBFFI_CFLAGS}" = "" ] ; then + LIBFFI_CFLAGS=$("${pkgconfig}" --cflags libffi) + fi + if [ "${LIBFFI_LIBS}" = "" ] ; then + LIBFFI_LIBS=$("${pkgconfig}" --libs libffi) + fi + fi + if [ "${LIBFFI_LIBS}" = "" ] ; then + LIBFFI_LIBS="-lffi" + fi + export LIBFFI_CFLAGS + export LIBFFI_LIBS +fi diff --git a/jdk/make/jprt.properties b/jdk/make/jprt.properties index 9535e7361e6..a2e0700b408 100644 --- a/jdk/make/jprt.properties +++ b/jdk/make/jprt.properties @@ -1,5 +1,5 @@ # -# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2006-2009 Sun Microsystems, Inc. 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,8 +34,8 @@ solaris_i586_5.10,\ solaris_x64_5.10,\ linux_i586_2.6,\ linux_x64_2.6,\ -windows_i586,\ -windows_x64 +windows_i586_5.0,\ +windows_x64_5.2 # The different build flavors we want jprt.build.flavors=product,fastdebug @@ -51,21 +51,37 @@ jprt.run.flavor.c2.option=-server jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10 jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 -# Standard list of jprt test targets for this workspace +# Standard test target for everybody jprt.test.targets=*-*-*-jvm98 -jprt.regression.test.targets= \ - *-product-*-java/lang, \ - *-product-*-java/security, \ - *-product-*-java/text, \ - *-product-*-java/util -#jprt.regression.test.targets= \ -# *-product-*-java/awt, \ -# *-product-*-java/beans, \ -# *-product-*-java/io, \ -# *-product-*-java/net, \ -# *-product-*-java/nio, \ -# *-product-*-java/rmi, \ +# Test targets in test/Makefile (some longer running tests only test c2) +jprt.make.rule.test.targets= \ + *-product-*-jdk_beans1, \ + *-product-*-jdk_beans2, \ + *-product-*-jdk_beans3, \ + *-product-*-jdk_io, \ + *-product-*-jdk_lang, \ + *-product-*-jdk_management1, \ + *-product-*-jdk_management2, \ + *-product-*-jdk_math, \ + *-product-*-jdk_misc, \ + *-product-*-jdk_net, \ + *-product-*-jdk_nio1, \ + *-product-*-jdk_nio2, \ + *-product-*-jdk_nio3, \ + *-product-*-jdk_security1, \ + *-product-*-jdk_security2, \ + *-product-*-jdk_security3, \ + *-product-*-jdk_text, \ + *-product-*-jdk_tools1, \ + *-product-*-jdk_tools2, \ + *-product-*-jdk_util + +# Some of these are crashing Xvfb or windows manager, need dedicated DISPLAY per test batch +jprt2.make.rule.test.targets= \ + *-product-*-jdk_awt, \ + *-product-*-jdk_rmi, \ + *-product-*-jdk_swing, \ # Directories needed to build jprt.bundle.exclude.src.dirs=build diff --git a/jdk/make/launchers/Makefile.launcher b/jdk/make/launchers/Makefile.launcher index 7e71e10bbd1..a9edb782b58 100644 --- a/jdk/make/launchers/Makefile.launcher +++ b/jdk/make/launchers/Makefile.launcher @@ -137,15 +137,15 @@ ifeq ($(PROGRAM),jdb) # PROGRAM, JAVA_ARGS, and APP_CLASSPATH are used in src/share/bin/java.c # SA is currently not available on windows (for any ARCH), or linux-ia64: ifneq ($(ARCH), ia64) - JDB_CLASSPATH = "{ \"/lib/tools.jar\", \"/lib/sa-jdi.jar\", \"/classes\" }" - OTHER_CPPFLAGS += -DAPP_CLASSPATH=$(JDB_CLASSPATH) + JDB_CLASSPATH = { "/lib/tools.jar", "/lib/sa-jdi.jar", "/classes" } + OTHER_CPPFLAGS += -DAPP_CLASSPATH='$(JDB_CLASSPATH)' endif endif # jconsole only ifeq ($(PROGRAM),jconsole) - JCONSOLE_CLASSPATH = "{ \"/lib/jconsole.jar\", \"/lib/tools.jar\", \"/classes\" }" - OTHER_CPPFLAGS += -DAPP_CLASSPATH=$(JCONSOLE_CLASSPATH) + JCONSOLE_CLASSPATH = { "/lib/jconsole.jar", "/lib/tools.jar", "/classes" } + OTHER_CPPFLAGS += -DAPP_CLASSPATH='$(JCONSOLE_CLASSPATH)' ifeq ($(PLATFORM), windows) OTHER_CPPFLAGS += -DJAVAW LDLIBS_COMMON += user32.lib @@ -163,8 +163,8 @@ endif # SA tools need special app classpath ifeq ($(SA_TOOL),true) - SA_CLASSPATH = "{ \"/lib/tools.jar\", \"/lib/sa-jdi.jar\", \"/classes\"}" - OTHER_CPPFLAGS += -DAPP_CLASSPATH=$(SA_CLASSPATH) + SA_CLASSPATH = { "/lib/tools.jar", "/lib/sa-jdi.jar", "/classes" } + OTHER_CPPFLAGS += -DAPP_CLASSPATH='$(SA_CLASSPATH)' endif # Wildcards @@ -173,11 +173,11 @@ ifeq ($(WILDCARDS),true) endif # Always tell native code what the main class is -OTHER_CPPFLAGS += -DMAIN_CLASS=\"$(MAIN_CLASS)\" +OTHER_CPPFLAGS += -DMAIN_CLASS='"$(MAIN_CLASS)"' # Construct initializer for initial arguments to java ALL_ARGS = -J-ms8m $(MAIN_JAVA_ARGS) $(MAIN_CLASS) $(MAIN_ARGS) -JAVA_ARGS = "{ $(ALL_ARGS:%=\"%\",) }" +JAVA_ARGS = { $(ALL_ARGS:%="%",) } # Always report launcher info build: launcher_info diff --git a/jdk/make/netbeans/jconsole/build.properties b/jdk/make/netbeans/jconsole/build.properties index dd442d93d20..6d675f49f69 100644 --- a/jdk/make/netbeans/jconsole/build.properties +++ b/jdk/make/netbeans/jconsole/build.properties @@ -33,7 +33,7 @@ includes=\ com/sun/tools/jconsole/ \ sun/tools/jconsole/ excludes=\ - sun/tools/jconsole/Version-template.java + sun/tools/jconsole/Version.java.template jtreg.tests=\ sun/tools/jconsole/ javadoc.packagenames=\ diff --git a/jdk/make/netbeans/jconsole/build.xml b/jdk/make/netbeans/jconsole/build.xml index 8d56df7c73d..d23ef05ffff 100644 --- a/jdk/make/netbeans/jconsole/build.xml +++ b/jdk/make/netbeans/jconsole/build.xml @@ -35,7 +35,7 @@ $@ diff --git a/jdk/make/sun/nio/Makefile b/jdk/make/sun/nio/Makefile index 8aa172250d6..e83c6f1f36d 100644 --- a/jdk/make/sun/nio/Makefile +++ b/jdk/make/sun/nio/Makefile @@ -44,14 +44,6 @@ include $(BUILDDIR)/common/Defs.gmk include FILES_java.gmk AUTO_FILES_JAVA_DIRS = sun/nio/cs/ext -# Exclude a few sources on windows -ifeq ($(PLATFORM), windows) - AUTO_JAVA_PRUNE = sun/nio/cs/ext/COMPOUND_TEXT.java \ - sun/nio/cs/ext/COMPOUND_TEXT_Decoder.java \ - sun/nio/cs/ext/COMPOUND_TEXT_Encoder.java \ - sun/nio/cs/ext/CompoundTextSupport.java -endif # PLATFORM - # For Cygwin, command line arguments that are paths must be converted to # windows style paths. These paths cannot be used as targets, however, because # the ":" in them will interfere with GNU Make rules, generating "multiple diff --git a/jdk/make/tools/Makefile b/jdk/make/tools/Makefile index 1fffa1bcaeb..d92550cdd95 100644 --- a/jdk/make/tools/Makefile +++ b/jdk/make/tools/Makefile @@ -38,7 +38,6 @@ SUBDIRS = \ compile_properties \ dir_diff \ dtdbuilder \ - fontchecker \ freetypecheck \ generate_break_iterator \ GenerateCharacter \ diff --git a/jdk/make/tools/src/build/tools/fontchecker/FontCheckDummy.java b/jdk/make/tools/src/build/tools/fontchecker/FontCheckDummy.java deleted file mode 100644 index a472a27d817..00000000000 --- a/jdk/make/tools/src/build/tools/fontchecker/FontCheckDummy.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2002-2004 Sun Microsystems, Inc. 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -package build.tools.fontchecker; - -import java.awt.*; -import java.awt.image.*; -import java.io.*; - -/** - * FontCheckDummy (not unlike Crash Test Dummy). - * - *
- * FontCheckDummy is the "child" process. Its task is to verify
- * integrity of system fonts. Since unexpected crashes are known
- * to occur when certain fonts are manipulated, the process is
- * "monitored" by the parent process, which might have to restart
- * the "child" if it crashes.
- * 
- * - * @author Ilya Bagrak - */ -public class FontCheckDummy implements FontCheckerConstants { - - /** - * Input stream from parent process. - */ - private BufferedReader is; - - /** - * Output stream to parent process. - */ - private BufferedOutputStream os; - - /** - * Image on which font characters will be drawn. - */ - private BufferedImage bi; - - /** - * graphics object on which characters will be drawn. - */ - private Graphics graphics; - - /** - * This constructor wraps the process's standard output and input streams - * to enable easier communication with parent process. It also initializes - * the graphics object used for drawing font characters. - *

- * @see FontCheckerConstants - */ - public FontCheckDummy() { - is = new BufferedReader(new InputStreamReader(System.in)); - os = new BufferedOutputStream(System.out); - /* make suffficient space for 12 point font */ - bi = new BufferedImage(40, 40, BufferedImage.TYPE_INT_RGB); - graphics = bi.getGraphics(); - try { - os.write(CHILD_STARTED_OK); - os.flush(); - } catch (IOException e) { - System.exit(-1); - } - } - - /** - * Initializes an instance of Font from given font path. - *
- * This methods attempts to create an instance of font from - * a string that represents path to the font file. - *

- * @param fontPath string representing path to font file - * @param flag indicating whether or not checking of non-TrueType fonts - * is necessary - */ - private void testFont(String fontPath, boolean checkNonTTF) { - - FontFileFilter fff = new FontFileFilter(checkNonTTF); - File fontFile = new File(fontPath); - if (!fontFile.canRead()) { - try { - os.write(ERR_FONT_NOT_FOUND); - os.flush(); - } catch (IOException e) { - System.exit(-1); - } - } - Font font = null; - try { - File file = new File(fontPath); - font = Font.createFont(fff.getFontType(fontPath), file); - } catch (FontFormatException e1) { - } catch (IOException e2) { - } - if (font == null) { - return; - } - font = font.deriveFont(Font.PLAIN, 12); - String name = font.getFontName(); - String family = font.getFamily(); - - char[] testChars = { '0' }; - if (font.canDisplay(testChars[0])) { - graphics.setFont(font); - graphics.drawChars(testChars, 0, 1, 20, 20); - } - try { - os.write(ERR_FONT_OK); - os.flush(); - } catch (IOException e) { - System.exit(-1); - } - } - - /** - * Begins synchronous communication betweeen parent and child processes. - *
- * This method begins communication between parent and child processes. - * FontCheckDummy reads a line of text from input stream (@see #is). - */ - public void run() { - String command = null; - while (true) { - try { - command = is.readLine(); - } catch (IOException e) { - System.exit(-1); - } - if (command != null && command.length() >= 1) { - int cmd = Integer.parseInt(command.substring(0,1)); - if (cmd == EXITCOMMAND) { - return; - } - boolean checkNonTTF = ((cmd == 1) ? true : false); - String fontPath = command.substring(1); - testFont(fontPath, checkNonTTF); - } else { - return; - } - } - } - - public static void main(String[] args) { - try { - /* Background app. */ - System.setProperty("java.awt.headless", "true"); - System.setProperty("sun.java2d.noddraw", "true"); - new FontCheckDummy().run(); - } catch (Throwable t) { - } - System.exit(0); - } -} diff --git a/jdk/make/tools/src/build/tools/fontchecker/FontChecker.java b/jdk/make/tools/src/build/tools/fontchecker/FontChecker.java deleted file mode 100644 index 552db25a9fc..00000000000 --- a/jdk/make/tools/src/build/tools/fontchecker/FontChecker.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright 2002-2004 Sun Microsystems, Inc. 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -package build.tools.fontchecker; - -import java.io.*; -import java.util.*; -import java.awt.event.*; -import sun.font.FontManager; - -/** - * FontChecker. - * - *
- * This is a FontChecker program. This class is a "parent" process
- * which invokes a "child" process. The child process will test
- * series of fonts and may crash as it encounters invalid fonts.
- * The "parent" process must then interpret error codes passed to it
- * by the "child" process and restart the "child" process if necessary.
- *
- * usage: java FontChecker [-v] -o outputfile
- *
- *        -o is the name of the file to contains canonical path names of
- *           bad fonts that are identified. This file is not created if
- *           no bad fonts are found.
- *        -v verbose: prints progress messages.
- *
- * 
- * - * @author Ilya Bagrak - */ -public class FontChecker implements ActionListener, FontCheckerConstants { - - /** - * Output stream to subprocess. - * Corresponds to the subprocess's System.in". - */ - private PrintWriter procPipeOut; - - /** - * Input stream from subprocess. - * Corresponds to the subprocess's System.out". - */ - private BufferedInputStream procPipeIn; - - /** - * Child process. - */ - private Process childProc; - - /** - * Name of output file to write file names of bad fonts - */ - private String outputFile; - - /** - * Reference to currently executing thread. - */ - private Thread currThread; - - /** - * Timeout timer for a single font check - */ - private javax.swing.Timer timeOne; - - /** - * Timeout timer for all font checks - */ - private javax.swing.Timer timeAll; - - /** - * max time (in milliseconds) allowed for checking a single font. - */ - private static int timeoutOne = 10000; - - /** - * max time (in milliseconds) allowed for checking all fonts. - */ - private static int timeoutAll = 120000; - - /** - * Boolean flag indicating whether FontChecker is required to - * check non-TrueType fonts. - */ - private boolean checkNonTTF = false; - - /** - * List of bad fonts found in the system. - */ - private Vector badFonts = new Vector(); - - /** - * whether to print warnings messges etc to stdout/err - * default is false - */ - private static boolean verbose = false; - - /* Command to use to exec sub-process. */ - private static String javaCmd = "java"; - - static void printlnMessage(String s) { - if (verbose) { - System.out.println(s); - } - } - - /** - * Event handler for timer event. - *
- * Stops the timer and interrupts the current thread which is - * still waiting on I/O from the child process. - *

- * @param evt timer event - */ - public void actionPerformed(ActionEvent evt) { - if (evt.getSource() == timeOne) { - timeOne.stop(); - printlnMessage("Child timed out: killing"); - childProc.destroy(); - } else { - doExit(); // went on too long (ie timeAll timed out). - } - } - - /** - * Initializes a FontChecker. - *
- * This method is usually called after an unrecoverable error has - * been detected and a child process has either crashed or is in bad - * state. The method creates a new child process from - * scratch and initializes it's input/output streams. - */ - public void initialize() { - try { - if (childProc != null) { - childProc.destroy(); - } - String fileSeparator = System.getProperty("file.separator"); - String javaHome = System.getProperty("java.home"); - String classPath = System.getProperty("java.class.path"); - classPath = "\"" + classPath + "\""; - String opt = "-cp " + classPath + " -Dsun.java2d.fontpath=\"" + - javaHome + fileSeparator + "lib" + fileSeparator + "fonts\""; - - /* command to exec the child process with the same JRE */ - String cmd = - new String(javaHome + fileSeparator + "bin" + - fileSeparator + javaCmd + - " -XXsuppressExitMessage " + opt + - " com.sun.java2d.fontchecker.FontCheckDummy"); - printlnMessage("cmd="+cmd); - childProc = Runtime.getRuntime().exec(cmd); - - } catch (IOException e) { - printlnMessage("can't execute child process"); - System.exit(0); - } catch (SecurityException e) { - printlnMessage("Error: access denied"); - System.exit(0); - } - - /* initialize input/output streams to/from child process */ - procPipeOut = new PrintWriter(childProc.getOutputStream()); - procPipeIn = new BufferedInputStream(childProc.getInputStream()); - - try { - int code = procPipeIn.read(); - if (code != CHILD_STARTED_OK) { - printlnMessage("bad child process start status="+code); - doExit(); - } - } catch (IOException e) { - printlnMessage("can't read child process start status unknown"); - doExit(); - } - } - - private void doExit() { - try { - if (procPipeOut != null) { - /* Tell the child to exit */ - procPipeOut.write(EXITCOMMAND+System.getProperty("line.separator")); - procPipeOut.flush(); - procPipeOut.close(); - } - } catch (Throwable t) { - } - System.exit(0); - } - - /** - * Tries to verify integrity of a font specified by a path. - *
- * This method is used to test whether a font specified by the given - * path is valid and does not crash the system. - *

- * @param fontPath a string representation of font path - * to standard out during while this font is tried - * @return returns true if font is OK, and - * false otherwise. - */ - public boolean tryFont(File fontFile) { - int bytesRead = 0; - String fontPath = fontFile.getAbsolutePath(); - - printlnMessage("Checking font "+fontPath); - - /* store reference to the current thread, so that when the timer - * fires it can be interrupted - */ - currThread = Thread.currentThread(); - timeOne.restart(); - - /* write a string command out to child process - * The command is formed by appending whether to test non-TT fonts - * and font path to be tested - */ - String command = Integer.toString(checkNonTTF ? 1 : 0) + - fontPath + - System.getProperty("line.separator"); - procPipeOut.write(command); - procPipeOut.flush(); - - /* check if underlying stream has encountered an error after - * command has been issued - */ - if (procPipeOut.checkError()){ - printlnMessage("Error: font crashed"); - initialize(); - return false; - } - - /* trying reading error code back from child process */ - try { - bytesRead = procPipeIn.read(); - } catch(InterruptedIOException e) { - /* A timeout timer fired before the operation completed */ - printlnMessage("Error: timeout occured"); - initialize(); - return false; - } catch(IOException e) { - /* there was an error reading from the stream */ - timeOne.stop(); - printlnMessage("Error: font crashed"); - initialize(); - return false; - } catch (Throwable t) { - bytesRead = ERR_FONT_READ_EXCPT; - } finally { - timeOne.stop(); - } - - if (bytesRead == ERR_FONT_OK) { - printlnMessage("Font integrity verified"); - return true; - } else if (bytesRead > 0) { - - switch(bytesRead){ - case ERR_FONT_NOT_FOUND: - printlnMessage("Error: font not found!"); - break; - case ERR_FONT_BAD_FORMAT: - printlnMessage("Error: incorrect font format"); - break; - case ERR_FONT_READ_EXCPT: - printlnMessage("Error: exception reading font"); - break; - case ERR_FONT_DISPLAY: - printlnMessage("Error: can't display characters"); - break; - case ERR_FONT_CRASH: - printlnMessage("Error: font crashed"); - break; - default: - printlnMessage("Error: invalid error code:"+bytesRead); - break; - - } - } else if (bytesRead == ERR_FONT_EOS) { - printlnMessage("Error: end of stream marker encountered"); - } else { - printlnMessage("Error: invalid error code:"+bytesRead); - } - - /* if we still haven't returned from this method, some error - * condition has occured and it is safer to re-initialize - */ - initialize(); - return false; - } - - /** - * Checks the integrity of all system fonts. - *
- * This method goes through every font in system's font path and verifies - * its integrity via the tryFont method. - *

- * @param restart true if checking of fonts should continue - * after the first bad font is found, and false otherwise - * @return returns true if all fonts are valid, - * false otherwise - * @see #tryFont(String, boolean, boolean) - */ - public boolean checkFonts(boolean restart) { - - /* file filter to filter out none-truetype font files */ - FontFileFilter fff = new FontFileFilter(checkNonTTF); - boolean checkOk = true; - - /* get platform-independent font path. Note that this bypasses - * the normal GraphicsEnvironment initialisation. In conjunction with - * the headless setting above, so we want to add - * java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(); - * to trigger a more normal initialisation. - */ - java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(); - String fontPath = FontManager.getFontPath(true); - StringTokenizer st = - new StringTokenizer(fontPath, - System.getProperty("path.separator")); - - /* some systems may have multiple font paths separated by - * platform-dependent characters, so fontPath string needs to be - * parsed - */ - timeOne = new javax.swing.Timer(timeoutOne, this); - timeAll = new javax.swing.Timer(timeoutAll, this); - timeAll.restart(); - while (st.hasMoreTokens()) { - File fontRoot = new File(st.nextToken()); - File[] fontFiles = fontRoot.listFiles(fff); - - for (int i = 0; i < fontFiles.length; i++) { - /* for each font file that is not a directory and passes - * through the font filter run the test - */ - if (!fontFiles[i].isDirectory() && - !tryFont(fontFiles[i])) { - - checkOk = false; - badFonts.add(fontFiles[i].getAbsolutePath()); - if (!restart) { - break; - } - } - } - } - - /* Tell the child to exit */ - procPipeOut.write(EXITCOMMAND+System.getProperty("line.separator")); - procPipeOut.flush(); - procPipeOut.close(); - - return checkOk; - } - - public static void main(String args[]){ - try { - /* Background app. */ - System.setProperty("java.awt.headless", "true"); - System.setProperty("sun.java2d.noddraw", "true"); - - boolean restart = true; - boolean errorFlag = false; - - FontChecker fc = new FontChecker(); - int arg = 0; - - while (arg < args.length && errorFlag == false) { - if (args[arg].equals("-v")) { - verbose = true; - } - else if (args[arg].equals("-w") && - System.getProperty("os.name", "unknown"). - startsWith("Windows")) { - javaCmd = "javaw"; - } - else if (args[arg].equals("-o")) { - /* set output file */ - if (++arg < args.length) - fc.outputFile = args[arg]; - else { - /* invalid argument format */ - printlnMessage("Error: invalid argument format"); - errorFlag = true; - } - } - else { - /* invalid command line argument */ - printlnMessage("Error: invalid argument value"); - errorFlag = true; - } - arg++; - } - - if (errorFlag || fc.outputFile == null) { - System.exit(0); - } - - File outfile = new File(fc.outputFile); - if (outfile.exists()) { - outfile.delete(); - } - - fc.initialize(); - - if (!fc.checkFonts(restart)) { - String[] badFonts = (String[])fc.badFonts.toArray(new String[0]); - if (badFonts.length > 0) { - printlnMessage("Bad Fonts:"); - try { - FileOutputStream fos = - new FileOutputStream(fc.outputFile); - PrintStream ps = new PrintStream(fos); - for (int i = 0; i < badFonts.length; i++) { - ps.println(badFonts[i]); - printlnMessage(badFonts[i]); - } - fos.close(); - } catch (IOException e) { - } - } - } else { - printlnMessage("No bad fonts found."); - } - } catch (Throwable t) { - } - System.exit(0); - } -} diff --git a/jdk/make/tools/src/build/tools/fontchecker/FontCheckerConstants.java b/jdk/make/tools/src/build/tools/fontchecker/FontCheckerConstants.java deleted file mode 100644 index 7ed764d0aee..00000000000 --- a/jdk/make/tools/src/build/tools/fontchecker/FontCheckerConstants.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2004 Sun Microsystems, Inc. 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -package build.tools.fontchecker; - -public interface FontCheckerConstants { - - /* code sent to indicate child process started OK */ - public static final int CHILD_STARTED_OK = 100; - - /* error codes returned from child process */ - public static final int ERR_FONT_OK = 65; - public static final int ERR_FONT_NOT_FOUND = 60; - public static final int ERR_FONT_BAD_FORMAT = 61; - public static final int ERR_FONT_READ_EXCPT = 62; - public static final int ERR_FONT_DISPLAY = 64; - public static final int ERR_FONT_EOS = -1; - /* nl char sent after child crashes */ - public static final int ERR_FONT_CRASH = 10; - - /* 0 and 1 are reserved, and commands can only be a single digit integer */ - public static final int EXITCOMMAND = 2; -} diff --git a/jdk/make/tools/src/build/tools/fontchecker/FontFileFilter.java b/jdk/make/tools/src/build/tools/fontchecker/FontFileFilter.java deleted file mode 100644 index d137281eaf3..00000000000 --- a/jdk/make/tools/src/build/tools/fontchecker/FontFileFilter.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2002-2003 Sun Microsystems, Inc. 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* - *
- * This class filters TrueType font files from other file
- * found in the font path.
- *
- * 
- * - * @author Ilya Bagrak - */ - -package build.tools.fontchecker; - -import java.awt.*; -import java.io.*; - -public class FontFileFilter implements java.io.FileFilter, FontCheckerConstants { - - /** - * Boolean flag indicating whether this filter filters out - * non-TrueType fonts. - */ - private boolean checkNonTTF; - - public FontFileFilter() { - this(false); - } - - public FontFileFilter(boolean checkNonTTF) { - super(); - this.checkNonTTF = checkNonTTF; - } - - /** - * Checks whether a file is accepted by this filter. - *
- * This method checks whehter a file is accepted by this filter. - * This filter is made to accept all the file whose extension is - * either .ttf or .TTF. These files are assumed to be TrueType fonts. - *

- * @return returns a boolean value indicating whether or not a file is - * accepted - */ - public boolean accept(File pathname) { - - String name = pathname.getName(); - return (name.endsWith(".ttf") || - name.endsWith(".TTF") || - name.endsWith(".ttc") || - name.endsWith(".TTC")) || - (name.endsWith(".pfb") || - name.endsWith(".PFB") || - name.endsWith(".pfa") || - name.endsWith(".PFA") && - checkNonTTF == true); - } - - public static int getFontType(String filename) { - if (filename.endsWith(".ttf") || - filename.endsWith(".TTF") || - filename.endsWith(".ttc") || - filename.endsWith(".TTC")) - return Font.TRUETYPE_FONT; - else if (filename.endsWith(".pfb") || - filename.endsWith(".PFB") || - filename.endsWith(".pfa") || - filename.endsWith(".PFA")) - return Font.TYPE1_FONT; - else - return 999; - } - -} diff --git a/jdk/make/tools/src/build/tools/fontchecker/README.txt b/jdk/make/tools/src/build/tools/fontchecker/README.txt deleted file mode 100644 index 0dfd696d0c2..00000000000 --- a/jdk/make/tools/src/build/tools/fontchecker/README.txt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2002-2003 Sun Microsystems, Inc. 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ -Instructions for running FontChecker ------------------------------------- - -FontChecker is a program designed to identify fonts that may cause JRE -crashes. Such fonts may be corrupted files, or badly constructed fonts. -Some crashes may also be due to bugs in the JRE's font code. -This test is designed to run quickly and silently as part of the JRE -installation process. It will only benefit users who install the JRE -via that mechanism. It cannot guarantee to identify all "bad fonts" because -the tests are minimal. Nor can it prevent problems due to fonts installed -subsequently to the JRE's installation. However it does ensure that the -vast majority of problem fonts are identified. This is important -"RAS" functionality. It is targeted at the consumer/plugin market where -there is substantial likelihood of end-users having installed software -packages which may be delivered with fonts that are not up to commercial -standards. - -The test is designed to be "fail safe". If the program fails to run -properly it has no impact on the installer or on JRE execution. -Thus there is no need to monitor successful execution of the test. - -The test is not a new "tool" in the sense of "javah" etc. -The test is not designed to be user executable or visible, and should -be unpacked by the installer into a temporary location, and executed -once the rest of the JRE is installed (ie as a postinstall step), and -can then be deleted from the temporary location once installation is -complete. Not deleting the jar file before execution is complete is -probably the sole reason that the installer may want to wait for -the program to complete. - -The FontChecker application can be run directly from the jar -file with this command: - %java -jar fontchecker.jar -o - -The output file is a required parameter in this version of the application. -The JRE installer should use the above form, and use it to create an -output file which must be named "badfonts.txt" and be placed into -the JRE's lib\fonts directory eg:- - - java -jar fontchecker.jar -o "C:\Program Files\jre\lib\fonts\badfonts.txt" - -Note the lower case "badfonts.txt", and the string quotes because of the spaces -in the path name. -The location given here is an example and needs to be calculated at install -time as $JREHOME\lib\fonts\badfonts.txt -The location and name are important, because the JRE at runtime will -look for this exactly located name and file. -This location is private to that JRE instance. It will not affect -any other JRE installed on the system. - -If running from a different directory than that containing the jar file, -use the form containing the full path to the jar file, eg : - - java -jar C:\fc\fontchecker.jar -o "C:\Program Files\jre\lib\fonts\badfonts.txt" - -FontChecker application accepts following command line flags. -usage: java -jar fontchecker.jar -o outputfile - -v - - -o is the name of the file to contains canonical path names of - bad fonts that are identified. This file is not created if - no bad fonts are found. - - -v verbose mode: print progress/warning messages. Not recommended - for installer use. - - -w if running on Windows, use "javaw" to exec the sub-process. diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java b/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java index f8e028d197b..388d7a1b6fb 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java @@ -62,6 +62,8 @@ import javax.imageio.event.IIOReadWarningListener; import java.io.*; import java.nio.*; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Iterator; import java.util.StringTokenizer; @@ -502,12 +504,18 @@ public class BMPImageReader extends ImageReader implements BMPConstants { iis.reset(); try { - if (metadata.colorSpace == PROFILE_LINKED) + if (metadata.colorSpace == PROFILE_LINKED && + isLinkedProfileAllowed() && + !isUncOrDevicePath(profile)) + { + String path = new String(profile, "windows-1252"); + colorSpace = - new ICC_ColorSpace(ICC_Profile.getInstance(new String(profile))); - else + new ICC_ColorSpace(ICC_Profile.getInstance(path)); + } else { colorSpace = new ICC_ColorSpace(ICC_Profile.getInstance(profile)); + } } catch (Exception e) { colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); } @@ -1745,4 +1753,69 @@ public class BMPImageReader extends ImageReader implements BMPConstants { public void sequenceStarted(ImageReader src, int minIndex) {} public void readAborted(ImageReader src) {} } + + private static Boolean isLinkedProfileDisabled = null; + + private static boolean isLinkedProfileAllowed() { + if (isLinkedProfileDisabled == null) { + PrivilegedAction a = new PrivilegedAction() { + public Boolean run() { + return Boolean.getBoolean("sun.imageio.plugins.bmp.disableLinkedProfiles"); + } + }; + isLinkedProfileDisabled = AccessController.doPrivileged(a); + } + return !isLinkedProfileDisabled; + } + + private static Boolean isWindowsPlatform = null; + + /** + * Verifies whether the byte array contans a unc path. + * Non-UNC path examples: + * c:\path\to\file - simple notation + * \\?\c:\path\to\file - long notation + * + * UNC path examples: + * \\server\share - a UNC path in simple notation + * \\?\UNC\server\share - a UNC path in long notation + * \\.\some\device - a path to device. + */ + private static boolean isUncOrDevicePath(byte[] p) { + if (isWindowsPlatform == null) { + PrivilegedAction a = new PrivilegedAction() { + public Boolean run() { + String osname = System.getProperty("os.name"); + return (osname != null && + osname.toLowerCase().startsWith("win")); + } + }; + isWindowsPlatform = AccessController.doPrivileged(a); + } + + if (!isWindowsPlatform) { + /* no need for the check on platforms except windows */ + return false; + } + + /* normalize prefix of the path */ + if (p[0] == '/') p[0] = '\\'; + if (p[1] == '/') p[1] = '\\'; + if (p[3] == '/') p[3] = '\\'; + + + if ((p[0] == '\\') && (p[1] == '\\')) { + if ((p[2] == '?') && (p[3] == '\\')) { + // long path: whether unc or local + return ((p[4] == 'U' || p[4] == 'u') && + (p[5] == 'N' || p[5] == 'n') && + (p[6] == 'C' || p[6] == 'c')); + } else { + // device path or short unc notation + return true; + } + } else { + return false; + } + } } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java index 5323b0ac786..bc3a224c091 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java @@ -25,6 +25,8 @@ package com.sun.java.swing.plaf.motif; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.border.*; import javax.swing.plaf.basic.*; @@ -46,16 +48,23 @@ import javax.swing.plaf.*; */ public class MotifButtonUI extends BasicButtonUI { - private final static MotifButtonUI motifButtonUI = new MotifButtonUI(); - protected Color selectColor; private boolean defaults_initialized = false; + private static final Object MOTIF_BUTTON_UI_KEY = new Object(); + // ******************************** // Create PLAF // ******************************** - public static ComponentUI createUI(JComponent c){ + public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + MotifButtonUI motifButtonUI = + (MotifButtonUI) appContext.get(MOTIF_BUTTON_UI_KEY); + if (motifButtonUI == null) { + motifButtonUI = new MotifButtonUI(); + appContext.put(MOTIF_BUTTON_UI_KEY, motifButtonUI); + } return motifButtonUI; } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java index a356b57caaf..a4354d26981 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java @@ -25,6 +25,8 @@ package com.sun.java.swing.plaf.motif; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.plaf.*; @@ -45,7 +47,7 @@ import java.awt.*; */ public class MotifCheckBoxUI extends MotifRadioButtonUI { - private static final MotifCheckBoxUI motifCheckBoxUI = new MotifCheckBoxUI(); + private static final Object MOTIF_CHECK_BOX_UI_KEY = new Object(); private final static String propertyPrefix = "CheckBox" + "."; @@ -55,7 +57,14 @@ public class MotifCheckBoxUI extends MotifRadioButtonUI { // ******************************** // Create PLAF // ******************************** - public static ComponentUI createUI(JComponent c){ + public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + MotifCheckBoxUI motifCheckBoxUI = + (MotifCheckBoxUI) appContext.get(MOTIF_CHECK_BOX_UI_KEY); + if (motifCheckBoxUI == null) { + motifCheckBoxUI = new MotifCheckBoxUI(); + appContext.put(MOTIF_CHECK_BOX_UI_KEY, motifCheckBoxUI); + } return motifCheckBoxUI; } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java index 7b040ea1c7f..bfa958857c8 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java @@ -25,6 +25,8 @@ package com.sun.java.swing.plaf.motif; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.plaf.basic.BasicLabelUI; import javax.swing.plaf.ComponentUI; @@ -44,9 +46,16 @@ import javax.swing.plaf.ComponentUI; */ public class MotifLabelUI extends BasicLabelUI { - static MotifLabelUI sharedInstance = new MotifLabelUI(); + private static final Object MOTIF_LABEL_UI_KEY = new Object(); public static ComponentUI createUI(JComponent c) { - return sharedInstance; + AppContext appContext = AppContext.getAppContext(); + MotifLabelUI motifLabelUI = + (MotifLabelUI) appContext.get(MOTIF_LABEL_UI_KEY); + if (motifLabelUI == null) { + motifLabelUI = new MotifLabelUI(); + appContext.put(MOTIF_LABEL_UI_KEY, motifLabelUI); + } + return motifLabelUI; } } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java index ea3769c2bc6..5029779bc9d 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java @@ -25,6 +25,8 @@ package com.sun.java.swing.plaf.motif; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.border.*; import javax.swing.plaf.basic.BasicRadioButtonUI; @@ -47,7 +49,7 @@ import java.awt.*; */ public class MotifRadioButtonUI extends BasicRadioButtonUI { - private static final MotifRadioButtonUI motifRadioButtonUI = new MotifRadioButtonUI(); + private static final Object MOTIF_RADIO_BUTTON_UI_KEY = new Object(); protected Color focusColor; @@ -57,6 +59,13 @@ public class MotifRadioButtonUI extends BasicRadioButtonUI { // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + MotifRadioButtonUI motifRadioButtonUI = + (MotifRadioButtonUI) appContext.get(MOTIF_RADIO_BUTTON_UI_KEY); + if (motifRadioButtonUI == null) { + motifRadioButtonUI = new MotifRadioButtonUI(); + appContext.put(MOTIF_RADIO_BUTTON_UI_KEY, motifRadioButtonUI); + } return motifRadioButtonUI; } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java index 43af4139dcc..984667e547e 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java @@ -25,6 +25,8 @@ package com.sun.java.swing.plaf.motif; +import sun.awt.AppContext; + import java.awt.*; import java.awt.event.*; @@ -48,7 +50,7 @@ import javax.swing.plaf.basic.*; */ public class MotifToggleButtonUI extends BasicToggleButtonUI { - private final static MotifToggleButtonUI motifToggleButtonUI = new MotifToggleButtonUI(); + private static final Object MOTIF_TOGGLE_BUTTON_UI_KEY = new Object(); protected Color selectColor; @@ -58,6 +60,13 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + MotifToggleButtonUI motifToggleButtonUI = + (MotifToggleButtonUI) appContext.get(MOTIF_TOGGLE_BUTTON_UI_KEY); + if (motifToggleButtonUI == null) { + motifToggleButtonUI = new MotifToggleButtonUI(); + appContext.put(MOTIF_TOGGLE_BUTTON_UI_KEY, motifToggleButtonUI); + } return motifToggleButtonUI; } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java index 4ebc563e0cd..2de1f4ec351 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java @@ -35,6 +35,7 @@ import java.awt.*; import static com.sun.java.swing.plaf.windows.TMSchema.*; import static com.sun.java.swing.plaf.windows.TMSchema.Part.*; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; +import sun.awt.AppContext; /** @@ -52,8 +53,6 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; */ public class WindowsButtonUI extends BasicButtonUI { - private final static WindowsButtonUI windowsButtonUI = new WindowsButtonUI(); - protected int dashedRectGapX; protected int dashedRectGapY; protected int dashedRectGapWidth; @@ -63,11 +62,19 @@ public class WindowsButtonUI extends BasicButtonUI private boolean defaults_initialized = false; + private static final Object WINDOWS_BUTTON_UI_KEY = new Object(); // ******************************** // Create PLAF // ******************************** - public static ComponentUI createUI(JComponent c){ + public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + WindowsButtonUI windowsButtonUI = + (WindowsButtonUI) appContext.get(WINDOWS_BUTTON_UI_KEY); + if (windowsButtonUI == null) { + windowsButtonUI = new WindowsButtonUI(); + appContext.put(WINDOWS_BUTTON_UI_KEY, windowsButtonUI); + } return windowsButtonUI; } @@ -151,7 +158,7 @@ public class WindowsButtonUI extends BasicButtonUI * allocating them in each paint call substantially reduced the time * it took paint to run. Obviously, this method can't be re-entered. */ - private static Rectangle viewRect = new Rectangle(); + private Rectangle viewRect = new Rectangle(); public void paint(Graphics g, JComponent c) { if (XPStyle.getXP() != null) { diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java index fa388195a4d..29c8221a66b 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java @@ -25,6 +25,8 @@ package com.sun.java.swing.plaf.windows; +import sun.awt.AppContext; + import javax.swing.plaf.basic.*; import javax.swing.*; import javax.swing.plaf.*; @@ -49,7 +51,7 @@ public class WindowsCheckBoxUI extends WindowsRadioButtonUI // of BasicCheckBoxUI because we want to pick up all the // painting changes made in MetalRadioButtonUI. - private static final WindowsCheckBoxUI windowsCheckBoxUI = new WindowsCheckBoxUI(); + private static final Object WINDOWS_CHECK_BOX_UI_KEY = new Object(); private final static String propertyPrefix = "CheckBox" + "."; @@ -59,6 +61,13 @@ public class WindowsCheckBoxUI extends WindowsRadioButtonUI // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + WindowsCheckBoxUI windowsCheckBoxUI = + (WindowsCheckBoxUI) appContext.get(WINDOWS_CHECK_BOX_UI_KEY); + if (windowsCheckBoxUI == null) { + windowsCheckBoxUI = new WindowsCheckBoxUI(); + appContext.put(WINDOWS_CHECK_BOX_UI_KEY, windowsCheckBoxUI); + } return windowsCheckBoxUI; } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java index 5abbf512de2..b0c74100999 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java @@ -26,6 +26,8 @@ package com.sun.java.swing.plaf.windows; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import java.awt.Color; import java.awt.Graphics; @@ -51,12 +53,19 @@ import javax.swing.plaf.basic.BasicLabelUI; */ public class WindowsLabelUI extends BasicLabelUI { - private final static WindowsLabelUI windowsLabelUI = new WindowsLabelUI(); + private static final Object WINDOWS_LABEL_UI_KEY = new Object(); // ******************************** // Create PLAF // ******************************** - public static ComponentUI createUI(JComponent c){ + public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + WindowsLabelUI windowsLabelUI = + (WindowsLabelUI) appContext.get(WINDOWS_LABEL_UI_KEY); + if (windowsLabelUI == null) { + windowsLabelUI = new WindowsLabelUI(); + appContext.put(WINDOWS_LABEL_UI_KEY, windowsLabelUI); + } return windowsLabelUI; } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java index 43665829347..9d784278780 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java @@ -25,6 +25,8 @@ package com.sun.java.swing.plaf.windows; +import sun.awt.AppContext; + import javax.swing.plaf.basic.*; import javax.swing.*; import javax.swing.plaf.*; @@ -44,7 +46,7 @@ import java.awt.*; */ public class WindowsRadioButtonUI extends BasicRadioButtonUI { - private static final WindowsRadioButtonUI windowsRadioButtonUI = new WindowsRadioButtonUI(); + private static final Object WINDOWS_RADIO_BUTTON_UI_KEY = new Object(); protected int dashedRectGapX; protected int dashedRectGapY; @@ -59,6 +61,13 @@ public class WindowsRadioButtonUI extends BasicRadioButtonUI // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + WindowsRadioButtonUI windowsRadioButtonUI = + (WindowsRadioButtonUI) appContext.get(WINDOWS_RADIO_BUTTON_UI_KEY); + if (windowsRadioButtonUI == null) { + windowsRadioButtonUI = new WindowsRadioButtonUI(); + appContext.put(WINDOWS_RADIO_BUTTON_UI_KEY, windowsRadioButtonUI); + } return windowsRadioButtonUI; } diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java index 3b49ad5ee4e..f7a8707aabe 100644 --- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java +++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java @@ -25,6 +25,8 @@ package com.sun.java.swing.plaf.windows; +import sun.awt.AppContext; + import javax.swing.plaf.basic.*; import javax.swing.border.*; import javax.swing.plaf.*; @@ -49,18 +51,25 @@ import java.beans.PropertyChangeEvent; */ public class WindowsToggleButtonUI extends BasicToggleButtonUI { - protected static int dashedRectGapX; - protected static int dashedRectGapY; - protected static int dashedRectGapWidth; - protected static int dashedRectGapHeight; + protected int dashedRectGapX; + protected int dashedRectGapY; + protected int dashedRectGapWidth; + protected int dashedRectGapHeight; protected Color focusColor; - private final static WindowsToggleButtonUI windowsToggleButtonUI = new WindowsToggleButtonUI(); + private static final Object WINDOWS_TOGGLE_BUTTON_UI_KEY = new Object(); private boolean defaults_initialized = false; public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + WindowsToggleButtonUI windowsToggleButtonUI = + (WindowsToggleButtonUI) appContext.get(WINDOWS_TOGGLE_BUTTON_UI_KEY); + if (windowsToggleButtonUI == null) { + windowsToggleButtonUI = new WindowsToggleButtonUI(); + appContext.put(WINDOWS_TOGGLE_BUTTON_UI_KEY, windowsToggleButtonUI); + } return windowsToggleButtonUI; } diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java index 2807e19d36f..364f000c839 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. 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 @@ -32,12 +32,8 @@ import java.io.IOException; import java.io.OutputStream; import java.io.InputStream; import java.net.Socket; -import java.util.Vector; -import java.util.Hashtable; import javax.naming.CommunicationException; -import javax.naming.AuthenticationException; -import javax.naming.AuthenticationNotSupportedException; import javax.naming.ServiceUnavailableException; import javax.naming.NamingException; import javax.naming.InterruptedNamingException; @@ -47,6 +43,8 @@ import javax.naming.ldap.Control; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import sun.misc.IOUtils; //import javax.net.SocketFactory; /** @@ -799,7 +797,6 @@ public final class Connection implements Runnable { byte inbuf[]; // Buffer for reading incoming bytes int inMsgId; // Message id of incoming response int bytesread; // Number of bytes in inbuf - int bytesleft; // Number of bytes that need to read for completing resp int br; // Temp; number of bytes read from stream int offset; // Offset of where to store bytes in inbuf int seqlen; // Length of ASN sequence @@ -811,7 +808,7 @@ public final class Connection implements Runnable { try { while (true) { try { - inbuf = new byte[2048]; + inbuf = new byte[10]; offset = 0; seqlen = 0; @@ -871,19 +868,10 @@ public final class Connection implements Runnable { } // read in seqlen bytes - bytesleft = seqlen; - if ((offset + bytesleft) > inbuf.length) { - byte nbuf[] = new byte[offset + bytesleft]; - System.arraycopy(inbuf, 0, nbuf, 0, offset); - inbuf = nbuf; - } - while (bytesleft > 0) { - bytesread = in.read(inbuf, offset, bytesleft); - if (bytesread < 0) - break; // EOF - offset += bytesread; - bytesleft -= bytesread; - } + byte[] left = IOUtils.readFully(in, seqlen, false); + inbuf = Arrays.copyOf(inbuf, offset + left.length); + System.arraycopy(left, 0, inbuf, offset, left.length); + offset += left.length; /* if (dump > 0) { System.err.println("seqlen: " + seqlen); diff --git a/jdk/src/share/classes/java/awt/KeyboardFocusManager.java b/jdk/src/share/classes/java/awt/KeyboardFocusManager.java index da94b624be0..fd412d8646e 100644 --- a/jdk/src/share/classes/java/awt/KeyboardFocusManager.java +++ b/jdk/src/share/classes/java/awt/KeyboardFocusManager.java @@ -53,7 +53,8 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.WeakHashMap; -import sun.util.logging.PlatformLogger; +import java.util.logging.Level; +import java.util.logging.Logger; import sun.awt.AppContext; import sun.awt.HeadlessToolkit; @@ -110,7 +111,7 @@ public abstract class KeyboardFocusManager { // Shared focus engine logger - private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.KeyboardFocusManager"); + private static final Logger focusLog = Logger.getLogger("java.awt.focus.KeyboardFocusManager"); static { /* ensure that the necessary native libraries are loaded */ @@ -153,7 +154,7 @@ public abstract class KeyboardFocusManager */ private static native void initIDs(); - private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.KeyboardFocusManager"); + private static final Logger log = Logger.getLogger("java.awt.KeyboardFocusManager"); /** * The identifier for the Forward focus traversal keys. @@ -503,8 +504,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return focusOwner; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -608,9 +609,9 @@ public abstract class KeyboardFocusManager } void setNativeFocusOwner(Component comp) { - if (focusLog.isLoggable(PlatformLogger.FINEST)) { - focusLog.finest("Calling peer {0} setCurrentFocusOwner for {1}", - peer, comp); + if (focusLog.isLoggable(Level.FINEST)) { + focusLog.log(Level.FINEST, "Calling peer {0} setCurrentFocusOwner for {1}", + new Object[] {String.valueOf(peer), String.valueOf(comp)}); } peer.setCurrentFocusOwner(comp); } @@ -672,8 +673,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return permanentFocusOwner; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -780,8 +781,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return focusedWindow; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -884,8 +885,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return activeWindow; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -918,8 +919,8 @@ public abstract class KeyboardFocusManager Window oldActiveWindow; synchronized (KeyboardFocusManager.class) { oldActiveWindow = getActiveWindow(); - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("Setting global active window to " + activeWindow + ", old active " + oldActiveWindow); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "Setting global active window to " + activeWindow + ", old active " + oldActiveWindow); } try { @@ -1214,8 +1215,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return currentFocusCycleRoot; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -2148,9 +2149,9 @@ public abstract class KeyboardFocusManager HeavyweightFocusRequest(Component heavyweight, Component descendant, boolean temporary, CausedFocusEvent.Cause cause) { - if (log.isLoggable(PlatformLogger.FINE)) { + if (log.isLoggable(Level.FINE)) { if (heavyweight == null) { - log.fine("Assertion (heavyweight != null) failed"); + log.log(Level.FINE, "Assertion (heavyweight != null) failed"); } } @@ -2160,12 +2161,12 @@ public abstract class KeyboardFocusManager } boolean addLightweightRequest(Component descendant, boolean temporary, CausedFocusEvent.Cause cause) { - if (log.isLoggable(PlatformLogger.FINE)) { + if (log.isLoggable(Level.FINE)) { if (this == HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { - log.fine("Assertion (this != HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) failed"); + log.log(Level.FINE, "Assertion (this != HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) failed"); } if (descendant == null) { - log.fine("Assertion (descendant != null) failed"); + log.log(Level.FINE, "Assertion (descendant != null) failed"); } } @@ -2338,12 +2339,12 @@ public abstract class KeyboardFocusManager (Component heavyweight, Component descendant, boolean temporary, boolean focusedWindowChangeAllowed, long time, CausedFocusEvent.Cause cause) { - if (log.isLoggable(PlatformLogger.FINE)) { + if (log.isLoggable(Level.FINE)) { if (heavyweight == null) { - log.fine("Assertion (heavyweight != null) failed"); + log.log(Level.FINE, "Assertion (heavyweight != null) failed"); } if (time == 0) { - log.fine("Assertion (time != 0) failed"); + log.log(Level.FINE, "Assertion (time != 0) failed"); } } @@ -2360,31 +2361,31 @@ public abstract class KeyboardFocusManager Component currentFocusOwner = thisManager.getGlobalFocusOwner(); Component nativeFocusOwner = thisManager.getNativeFocusOwner(); Window nativeFocusedWindow = thisManager.getNativeFocusedWindow(); - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("SNFH for {0} in {1}", - descendant, heavyweight); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "SNFH for {0} in {1}", + new Object[] {String.valueOf(descendant), String.valueOf(heavyweight)}); } - if (focusLog.isLoggable(PlatformLogger.FINEST)) { - focusLog.finest("0. Current focus owner {0}", - currentFocusOwner); - focusLog.finest("0. Native focus owner {0}", - nativeFocusOwner); - focusLog.finest("0. Native focused window {0}", - nativeFocusedWindow); + if (focusLog.isLoggable(Level.FINEST)) { + focusLog.log(Level.FINEST, "0. Current focus owner {0}", + String.valueOf(currentFocusOwner)); + focusLog.log(Level.FINEST, "0. Native focus owner {0}", + String.valueOf(nativeFocusOwner)); + focusLog.log(Level.FINEST, "0. Native focused window {0}", + String.valueOf(nativeFocusedWindow)); } synchronized (heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = getLastHWRequest(); - if (focusLog.isLoggable(PlatformLogger.FINEST)) { - focusLog.finest("Request {0}", hwFocusRequest); + if (focusLog.isLoggable(Level.FINEST)) { + focusLog.log(Level.FINEST, "Request {0}", String.valueOf(hwFocusRequest)); } if (hwFocusRequest == null && heavyweight == nativeFocusOwner) { if (descendant == currentFocusOwner) { // Redundant request. - if (focusLog.isLoggable(PlatformLogger.FINEST)) - focusLog.finest("1. SNFH_FAILURE for {0}", - descendant); + if (focusLog.isLoggable(Level.FINEST)) + focusLog.log(Level.FINEST, "1. SNFH_FAILURE for {0}", + String.valueOf(descendant)); return SNFH_FAILURE; } @@ -2416,8 +2417,8 @@ public abstract class KeyboardFocusManager // SunToolkit.postPriorityEvent(newFocusOwnerEvent); SunToolkit.postEvent(descendant.appContext, newFocusOwnerEvent); - if (focusLog.isLoggable(PlatformLogger.FINEST)) - focusLog.finest("2. SNFH_HANDLED for {0}", descendant); + if (focusLog.isLoggable(Level.FINEST)) + focusLog.log(Level.FINEST, "2. SNFH_HANDLED for {0}", String.valueOf(descendant)); return SNFH_SUCCESS_HANDLED; } else if (hwFocusRequest != null && hwFocusRequest.heavyweight == heavyweight) { @@ -2430,7 +2431,7 @@ public abstract class KeyboardFocusManager manager.enqueueKeyEvents(time, descendant); } - if (focusLog.isLoggable(PlatformLogger.FINEST)) + if (focusLog.isLoggable(Level.FINEST)) focusLog.finest("3. SNFH_HANDLED for lightweight" + descendant + " in " + heavyweight); return SNFH_SUCCESS_HANDLED; @@ -2453,7 +2454,7 @@ public abstract class KeyboardFocusManager (hwFocusRequest != null) ? hwFocusRequest.heavyweight : nativeFocusedWindow)) { - if (focusLog.isLoggable(PlatformLogger.FINEST)) + if (focusLog.isLoggable(Level.FINEST)) focusLog.finest("4. SNFH_FAILURE for " + descendant); return SNFH_FAILURE; } @@ -2463,7 +2464,7 @@ public abstract class KeyboardFocusManager heavyweightRequests.add (new HeavyweightFocusRequest(heavyweight, descendant, temporary, cause)); - if (focusLog.isLoggable(PlatformLogger.FINEST)) + if (focusLog.isLoggable(Level.FINEST)) focusLog.finest("5. SNFH_PROCEED for " + descendant); return SNFH_SUCCESS_PROCEED; } @@ -2854,13 +2855,14 @@ public abstract class KeyboardFocusManager } KeyboardFocusManager manager = getCurrentKeyboardFocusManager(); - if (focusLog.isLoggable(PlatformLogger.FINER)) { + if (focusLog.isLoggable(Level.FINER)) { if (event instanceof FocusEvent || event instanceof WindowEvent) { - focusLog.finer(">>> {0}", event); + focusLog.log(Level.FINER, ">>> {0}", new Object[] {String.valueOf(event)}); } - if (focusLog.isLoggable(PlatformLogger.FINER) && event instanceof KeyEvent) { - focusLog.finer(" focus owner is {0}", manager.getGlobalFocusOwner()); - focusLog.finer(">>> {0}", event); + if (focusLog.isLoggable(Level.FINER) && event instanceof KeyEvent) { + focusLog.log(Level.FINER, " focus owner is {0}", + new Object[] {String.valueOf(manager.getGlobalFocusOwner())}); + focusLog.log(Level.FINER, ">>> {0}", new Object[] {String.valueOf(event)}); } } @@ -2944,9 +2946,9 @@ public abstract class KeyboardFocusManager } } static void removeLastFocusRequest(Component heavyweight) { - if (log.isLoggable(PlatformLogger.FINE)) { + if (log.isLoggable(Level.FINE)) { if (heavyweight == null) { - log.fine("Assertion (heavyweight != null) failed"); + log.log(Level.FINE, "Assertion (heavyweight != null) failed"); } } diff --git a/jdk/src/share/classes/java/awt/color/ICC_Profile.java b/jdk/src/share/classes/java/awt/color/ICC_Profile.java index 78ba43d4bc4..488e6f4d299 100644 --- a/jdk/src/share/classes/java/awt/color/ICC_Profile.java +++ b/jdk/src/share/classes/java/awt/color/ICC_Profile.java @@ -865,7 +865,9 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_PYCC: synchronized(ICC_Profile.class) { if (PYCCprofile == null) { - if (getProfileFile("PYCC.pf") != null) { + if (!sun.jkernel.DownloadManager.isJREComplete() || + standardProfileExists("PYCC.pf")) + { ProfileDeferralInfo pInfo = new ProfileDeferralInfo("PYCC.pf", ColorSpace.TYPE_3CLR, 3, @@ -963,15 +965,15 @@ public class ICC_Profile implements Serializable { * and it does not permit read access to the given file. */ public static ICC_Profile getInstance(String fileName) throws IOException { - ICC_Profile thisProfile; - FileInputStream fis; + ICC_Profile thisProfile; + FileInputStream fis = null; - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkRead(fileName); + + File f = getProfileFile(fileName); + if (f != null) { + fis = new FileInputStream(f); } - - if ((fis = openProfile(fileName)) == null) { + if (fis == null) { throw new IOException("Cannot open file " + fileName); } @@ -1083,11 +1085,22 @@ public class ICC_Profile implements Serializable { void activateDeferredProfile() throws ProfileDataException { byte profileData[]; FileInputStream fis; - String fileName = deferralInfo.filename; + final String fileName = deferralInfo.filename; profileActivator = null; deferralInfo = null; - if ((fis = openProfile(fileName)) == null) { + PrivilegedAction pa = new PrivilegedAction() { + public FileInputStream run() { + File f = getStandardProfileFile(fileName); + if (f != null) { + try { + return new FileInputStream(f); + } catch (FileNotFoundException e) {} + } + return null; + } + }; + if ((fis = AccessController.doPrivileged(pa)) == null) { throw new ProfileDataException("Cannot open file " + fileName); } try { @@ -1786,59 +1799,36 @@ public class ICC_Profile implements Serializable { * available, such as a profile for sRGB. Built-in profiles use .pf as * the file name extension for profiles, e.g. sRGB.pf. */ - private static FileInputStream openProfile(final String fileName) { - return (FileInputStream)java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - File f = privilegedGetProfileFile(fileName); - if (f != null) { - try { - return new FileInputStream(f); - } catch (FileNotFoundException e) { - } - } - return null; - } - }); - } - - private static File getProfileFile(final String fileName) { - return (File)java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - return privilegedGetProfileFile(fileName); - } - }); - } - - /* - * this version is called from doPrivileged in openProfile - * or getProfileFile, so the whole method is privileged! - */ - - private static File privilegedGetProfileFile(String fileName) { + private static File getProfileFile(String fileName) { String path, dir, fullPath; File f = new File(fileName); /* try absolute file name */ - + if (f.isAbsolute()) { + /* Rest of code has little sense for an absolute pathname, + so return here. */ + return f.isFile() ? f : null; + } if ((!f.isFile()) && ((path = System.getProperty("java.iccprofile.path")) != null)){ /* try relative to java.iccprofile.path */ StringTokenizer st = new StringTokenizer(path, File.pathSeparator); - while (st.hasMoreTokens() && (!f.isFile())) { + while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) { dir = st.nextToken(); fullPath = dir + File.separatorChar + fileName; f = new File(fullPath); + if (!isChildOf(f, dir)) { + f = null; + } } } - if ((!f.isFile()) && + if (((f == null) || (!f.isFile())) && ((path = System.getProperty("java.class.path")) != null)) { /* try relative to java.class.path */ StringTokenizer st = new StringTokenizer(path, File.pathSeparator); - while (st.hasMoreTokens() && (!f.isFile())) { + while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) { dir = st.nextToken(); fullPath = dir + File.separatorChar + fileName; f = new File(fullPath); @@ -1858,13 +1848,69 @@ public class ICC_Profile implements Serializable { } } } - - if (f.isFile()) { + if ((f == null) || (!f.isFile())) { + /* try the directory of built-in profiles */ + f = getStandardProfileFile(fileName); + } + if (f != null && f.isFile()) { return f; } return null; } + /** + * Returns a file object corresponding to a built-in profile + * specified by fileName. + * If there is no built-in profile with such name, then the method + * returns null. + */ + private static File getStandardProfileFile(String fileName) { + String dir = System.getProperty("java.home") + + File.separatorChar + "lib" + File.separatorChar + "cmm"; + String fullPath = dir + File.separatorChar + fileName; + File f = new File(fullPath); + if (!f.isFile()) { + //make sure file was installed in the kernel mode + try { + //kernel uses platform independent paths => + // should not use platform separator char + sun.jkernel.DownloadManager.downloadFile("lib/cmm/"+fileName); + } catch (IOException ioe) {} + } + return (f.isFile() && isChildOf(f, dir)) ? f : null; + } + + /** + * Checks whether given file resides inside give directory. + */ + private static boolean isChildOf(File f, String dirName) { + try { + File dir = new File(dirName); + String canonicalDirName = dir.getCanonicalPath(); + if (!canonicalDirName.endsWith(File.separator)) { + canonicalDirName += File.separator; + } + String canonicalFileName = f.getCanonicalPath(); + return canonicalFileName.startsWith(canonicalDirName); + } catch (IOException e) { + /* we do not expect the IOException here, because invocation + * of this function is always preceeded by isFile() call. + */ + return false; + } + } + + /** + * Checks whether built-in profile specified by fileName exists. + */ + private static boolean standardProfileExists(final String fileName) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + return getStandardProfileFile(fileName) != null; + } + }); + } + /* * Serialization support. diff --git a/jdk/src/share/classes/java/beans/MetaData.java b/jdk/src/share/classes/java/beans/MetaData.java index fa67901b7a1..4827d785b38 100644 --- a/jdk/src/share/classes/java/beans/MetaData.java +++ b/jdk/src/share/classes/java/beans/MetaData.java @@ -42,12 +42,11 @@ import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; import java.security.AccessController; import java.security.PrivilegedAction; -import java.sql.Timestamp; - import java.util.*; import javax.swing.Box; @@ -290,13 +289,44 @@ class java_util_Date_PersistenceDelegate extends PersistenceDelegate { * @author Sergey A. Malenkov */ final class java_sql_Timestamp_PersistenceDelegate extends java_util_Date_PersistenceDelegate { - protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) { - Timestamp oldTime = (Timestamp)oldInstance; - Timestamp newTime = (Timestamp)newInstance; + private static final Method getNanosMethod = getNanosMethod(); - int nanos = oldTime.getNanos(); - if (nanos != newTime.getNanos()) { - out.writeStatement(new Statement(oldTime, "setNanos", new Object[] {nanos})); + private static Method getNanosMethod() { + try { + Class c = Class.forName("java.sql.Timestamp", true, null); + return c.getMethod("getNanos"); + } catch (ClassNotFoundException e) { + return null; + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** + * Invoke Timstamp getNanos. + */ + private static int getNanos(Object obj) { + if (getNanosMethod == null) + throw new AssertionError("Should not get here"); + try { + return (Integer)getNanosMethod.invoke(obj); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException) + throw (RuntimeException)cause; + if (cause instanceof Error) + throw (Error)cause; + throw new AssertionError(e); + } catch (IllegalAccessException iae) { + throw new AssertionError(iae); + } + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) { + // assumes oldInstance and newInstance are Timestamps + int nanos = getNanos(oldInstance); + if (nanos != getNanos(newInstance)) { + out.writeStatement(new Statement(oldInstance, "setNanos", new Object[] {nanos})); } } } diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java index bd59d95667a..323240b395c 100644 --- a/jdk/src/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/share/classes/java/lang/ClassLoader.java @@ -186,11 +186,6 @@ public abstract class ClassLoader { parallelLoaders.add(ClassLoader.class); } - // If initialization succeed this is set to true and security checks will - // succeed. Otherwise the object is not initialized and the object is - // useless. - private final boolean initialized; - // The parent class loader for delegation // Note: VM hardcoded the offset of this field, thus all new fields // must be added *after* it. @@ -232,6 +227,31 @@ public abstract class ClassLoader { private final HashMap packages = new HashMap(); + private static Void checkCreateClassLoader() { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + return null; + } + + private ClassLoader(Void unused, ClassLoader parent) { + this.parent = parent; + if (parallelLoaders.contains(this.getClass())) { + parallelLockMap = new ConcurrentHashMap(); + package2certs = new ConcurrentHashMap(); + domains = + Collections.synchronizedSet(new HashSet()); + assertionLock = new Object(); + } else { + // no finer-grained lock; lock on the classloader instance + parallelLockMap = null; + package2certs = new Hashtable(); + domains = new HashSet(); + assertionLock = this; + } + } + /** * Creates a new class loader using the specified parent class loader for * delegation. @@ -252,25 +272,7 @@ public abstract class ClassLoader { * @since 1.2 */ protected ClassLoader(ClassLoader parent) { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkCreateClassLoader(); - } - this.parent = parent; - if (parallelLoaders.contains(this.getClass())) { - parallelLockMap = new ConcurrentHashMap(); - package2certs = new ConcurrentHashMap(); - domains = - Collections.synchronizedSet(new HashSet()); - assertionLock = new Object(); - } else { - // no finer-grained lock; lock on the classloader instance - parallelLockMap = null; - package2certs = new Hashtable(); - domains = new HashSet(); - assertionLock = this; - } - initialized = true; + this(checkCreateClassLoader(), parent); } /** @@ -289,25 +291,7 @@ public abstract class ClassLoader { * of a new class loader. */ protected ClassLoader() { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkCreateClassLoader(); - } - this.parent = getSystemClassLoader(); - if (parallelLoaders.contains(this.getClass())) { - parallelLockMap = new ConcurrentHashMap(); - package2certs = new ConcurrentHashMap(); - domains = - Collections.synchronizedSet(new HashSet()); - assertionLock = new Object(); - } else { - // no finer-grained lock; lock on the classloader instance - parallelLockMap = null; - package2certs = new Hashtable(); - domains = new HashSet(); - assertionLock = this; - } - initialized = true; + this(checkCreateClassLoader(), getSystemClassLoader()); } // -- Class -- @@ -754,7 +738,6 @@ public abstract class ClassLoader { ProtectionDomain protectionDomain) throws ClassFormatError { - check(); protectionDomain = preDefineClass(name, protectionDomain); Class c = null; @@ -838,8 +821,6 @@ public abstract class ClassLoader { ProtectionDomain protectionDomain) throws ClassFormatError { - check(); - int len = b.remaining(); // Use byte[] if not a direct ByteBufer: @@ -984,7 +965,6 @@ public abstract class ClassLoader { * @see #defineClass(String, byte[], int, int) */ protected final void resolveClass(Class c) { - check(); resolveClass0(c); } @@ -1015,7 +995,6 @@ public abstract class ClassLoader { protected final Class findSystemClass(String name) throws ClassNotFoundException { - check(); ClassLoader system = getSystemClassLoader(); if (system == null) { if (!checkName(name)) @@ -1035,7 +1014,6 @@ public abstract class ClassLoader { */ private Class findBootstrapClassOrNull(String name) { - check(); if (!checkName(name)) return null; return findBootstrapClass(name); @@ -1044,13 +1022,6 @@ public abstract class ClassLoader { // return null if not found private native Class findBootstrapClass(String name); - // Check to make sure the class loader has been initialized. - private void check() { - if (!initialized) { - throw new SecurityException("ClassLoader object not initialized"); - } - } - /** * Returns the class with the given binary name if this * loader has been recorded by the Java virtual machine as an initiating @@ -1066,7 +1037,6 @@ public abstract class ClassLoader { * @since 1.1 */ protected final Class findLoadedClass(String name) { - check(); if (!checkName(name)) return null; return findLoadedClass0(name); @@ -1087,7 +1057,6 @@ public abstract class ClassLoader { * @since 1.1 */ protected final void setSigners(Class c, Object[] signers) { - check(); c.setSigners(signers); } @@ -2205,3 +2174,4 @@ class SystemClassLoaderAction return sys; } } + diff --git a/jdk/src/share/classes/java/math/BigInteger.java b/jdk/src/share/classes/java/math/BigInteger.java index a00c6633fc5..d7d4f19f040 100644 --- a/jdk/src/share/classes/java/math/BigInteger.java +++ b/jdk/src/share/classes/java/math/BigInteger.java @@ -288,11 +288,11 @@ public class BigInteger extends Number implements Comparable { */ public BigInteger(String val, int radix) { int cursor = 0, numDigits; - int len = val.length(); + final int len = val.length(); if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) throw new NumberFormatException("Radix out of range"); - if (val.length() == 0) + if (len == 0) throw new NumberFormatException("Zero length BigInteger"); // Check for at most one leading sign @@ -303,7 +303,7 @@ public class BigInteger extends Number implements Comparable { // No leading sign character or at most one leading sign character if (index1 == 0 || index2 == 0) { cursor = 1; - if (val.length() == 1) + if (len == 1) throw new NumberFormatException("Zero length BigInteger"); } if (index1 == 0) @@ -342,7 +342,7 @@ public class BigInteger extends Number implements Comparable { // Process remaining digit groups int superRadix = intRadix[radix]; int groupVal = 0; - while (cursor < val.length()) { + while (cursor < len) { group = val.substring(cursor, cursor += digitsPerInt[radix]); groupVal = Integer.parseInt(group, radix); if (groupVal < 0) diff --git a/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java b/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template similarity index 100% rename from jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java rename to jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template diff --git a/jdk/src/share/classes/java/nio/Direct-X-Buffer-bin.java b/jdk/src/share/classes/java/nio/Direct-X-Buffer-bin.java.template similarity index 100% rename from jdk/src/share/classes/java/nio/Direct-X-Buffer-bin.java rename to jdk/src/share/classes/java/nio/Direct-X-Buffer-bin.java.template diff --git a/jdk/src/share/classes/java/nio/Direct-X-Buffer.java b/jdk/src/share/classes/java/nio/Direct-X-Buffer.java.template similarity index 100% rename from jdk/src/share/classes/java/nio/Direct-X-Buffer.java rename to jdk/src/share/classes/java/nio/Direct-X-Buffer.java.template diff --git a/jdk/src/share/classes/java/nio/Heap-X-Buffer.java b/jdk/src/share/classes/java/nio/Heap-X-Buffer.java.template similarity index 100% rename from jdk/src/share/classes/java/nio/Heap-X-Buffer.java rename to jdk/src/share/classes/java/nio/Heap-X-Buffer.java.template diff --git a/jdk/src/share/classes/java/nio/X-Buffer-bin.java b/jdk/src/share/classes/java/nio/X-Buffer-bin.java.template similarity index 100% rename from jdk/src/share/classes/java/nio/X-Buffer-bin.java rename to jdk/src/share/classes/java/nio/X-Buffer-bin.java.template diff --git a/jdk/src/share/classes/java/nio/X-Buffer.java b/jdk/src/share/classes/java/nio/X-Buffer.java.template similarity index 100% rename from jdk/src/share/classes/java/nio/X-Buffer.java rename to jdk/src/share/classes/java/nio/X-Buffer.java.template diff --git a/jdk/src/share/classes/java/nio/charset/Charset-X-Coder.java b/jdk/src/share/classes/java/nio/charset/Charset-X-Coder.java.template similarity index 100% rename from jdk/src/share/classes/java/nio/charset/Charset-X-Coder.java rename to jdk/src/share/classes/java/nio/charset/Charset-X-Coder.java.template diff --git a/jdk/src/share/classes/java/security/MessageDigest.java b/jdk/src/share/classes/java/security/MessageDigest.java index 9ff8390d92d..f08b6fd9502 100644 --- a/jdk/src/share/classes/java/security/MessageDigest.java +++ b/jdk/src/share/classes/java/security/MessageDigest.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. 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 @@ -414,16 +414,17 @@ public abstract class MessageDigest extends MessageDigestSpi { * * @return true if the digests are equal, false otherwise. */ - public static boolean isEqual(byte digesta[], byte digestb[]) { - if (digesta.length != digestb.length) + public static boolean isEqual(byte[] digesta, byte[] digestb) { + if (digesta.length != digestb.length) { return false; - - for (int i = 0; i < digesta.length; i++) { - if (digesta[i] != digestb[i]) { - return false; - } } - return true; + + int result = 0; + // time-constant comparison + for (int i = 0; i < digesta.length; i++) { + result |= digesta[i] ^ digestb[i]; + } + return result == 0; } /** diff --git a/jdk/src/share/classes/java/util/AbstractList.java b/jdk/src/share/classes/java/util/AbstractList.java index bfbac714336..7f02aa44a06 100644 --- a/jdk/src/share/classes/java/util/AbstractList.java +++ b/jdk/src/share/classes/java/util/AbstractList.java @@ -256,9 +256,8 @@ public abstract class AbstractList extends AbstractCollection implements L public boolean addAll(int index, Collection c) { rangeCheckForAdd(index); boolean modified = false; - Iterator e = c.iterator(); - while (e.hasNext()) { - add(index++, e.next()); + for (E e : c) { + add(index++, e); modified = true; } return modified; diff --git a/jdk/src/share/classes/java/util/AbstractQueue.java b/jdk/src/share/classes/java/util/AbstractQueue.java index f13eba8e9b0..6925334eb8b 100644 --- a/jdk/src/share/classes/java/util/AbstractQueue.java +++ b/jdk/src/share/classes/java/util/AbstractQueue.java @@ -183,11 +183,9 @@ public abstract class AbstractQueue if (c == this) throw new IllegalArgumentException(); boolean modified = false; - Iterator e = c.iterator(); - while (e.hasNext()) { - if (add(e.next())) + for (E e : c) + if (add(e)) modified = true; - } return modified; } diff --git a/jdk/src/share/classes/java/util/Arrays.java b/jdk/src/share/classes/java/util/Arrays.java index f51fcac80a9..9aa9045f032 100644 --- a/jdk/src/share/classes/java/util/Arrays.java +++ b/jdk/src/share/classes/java/util/Arrays.java @@ -57,51 +57,14 @@ public class Arrays { // Suppresses default constructor, ensuring non-instantiability. private Arrays() {} - // Sorting + /* + * Sorting of primitive type arrays. + */ /** * Sorts the specified array into ascending numerical order. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - */ - public static void sort(long[] a) { - sort(a, 0, a.length); - } - - /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, to be sorted - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(long[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically @@ -110,37 +73,76 @@ public class Arrays { * @param a the array to be sorted */ public static void sort(int[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * * @throws IllegalArgumentException if {@code fromIndex > toIndex} * @throws ArrayIndexOutOfBoundsException * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(int[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** * Sorts the specified array into ascending numerical order. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(long[] a) { + DualPivotQuicksort.sort(a); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(long[] a, int fromIndex, int toIndex) { + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically @@ -149,37 +151,37 @@ public class Arrays { * @param a the array to be sorted */ public static void sort(short[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * * @throws IllegalArgumentException if {@code fromIndex > toIndex} * @throws ArrayIndexOutOfBoundsException * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(short[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** * Sorts the specified array into ascending numerical order. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically @@ -188,37 +190,37 @@ public class Arrays { * @param a the array to be sorted */ public static void sort(char[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * * @throws IllegalArgumentException if {@code fromIndex > toIndex} * @throws ArrayIndexOutOfBoundsException * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(char[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** * Sorts the specified array into ascending numerical order. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically @@ -227,160 +229,45 @@ public class Arrays { * @param a the array to be sorted */ public static void sort(byte[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * * @throws IllegalArgumentException if {@code fromIndex > toIndex} * @throws ArrayIndexOutOfBoundsException * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(byte[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** * Sorts the specified array into ascending numerical order. * - *

The {@code <} relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * {@code -0.0d == 0.0d} is {@code true} and a NaN value compares - * neither less than, greater than, nor equal to any floating-point - * value, even itself. To allow the sort to proceed, instead of using - * the {@code <} relation to determine ascending numerical order, - * this method uses the total order imposed by {@link Double#compareTo}. - * This ordering differs from the {@code <} relation in that {@code -0.0d} - * is treated as less than {@code 0.0d} and NaN is considered greater than - * any other floating-point value. For the purposes of sorting, all NaN - * values are considered equivalent and equal. + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - */ - public static void sort(double[] a) { - sort(a, 0, a.length); - } - - /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

The {@code <} relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * {@code -0.0d == 0.0d} is {@code true} and a NaN value compares - * neither less than, greater than, nor equal to any floating-point - * value, even itself. To allow the sort to proceed, instead of using - * the {@code <} relation to determine ascending numerical order, - * this method uses the total order imposed by {@link Double#compareTo}. - * This ordering differs from the {@code <} relation in that {@code -0.0d} - * is treated as less than {@code 0.0d} and NaN is considered greater than - * any other floating-point value. For the purposes of sorting, all NaN - * values are considered equivalent and equal. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, to be sorted - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(double[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sortNegZeroAndNaN(a, fromIndex, toIndex); - } - - private static void sortNegZeroAndNaN(double[] a, int fromIndex, int toIndex) { - final long NEG_ZERO_BITS = Double.doubleToLongBits(-0.0d); - /* - * The sort is done in three phases to avoid the expense of using - * NaN and -0.0d aware comparisons during the main sort. - * - * Preprocessing phase: move any NaN's to end of array, count the - * number of -0.0d's, and turn them into 0.0d's. - */ - int numNegZeros = 0; - int i = fromIndex; - int n = toIndex; - double temp; - - while (i < n) { - if (a[i] != a[i]) { - n--; - temp = a[i]; - a[i] = a[n]; - a[n] = temp; - } - else { - if (a[i] == 0 && Double.doubleToLongBits(a[i]) == NEG_ZERO_BITS) { - a[i] = 0.0d; - numNegZeros++; - } - i++; - } - } - // Main sort phase: quicksort everything but the NaN's - DualPivotQuicksort.sort(a, fromIndex, n - 1); - - // Postprocessing phase: change 0.0d's to -0.0d's as required - if (numNegZeros != 0) { - int j = binarySearch0(a, fromIndex, n, 0.0d); // position of ANY zero - - do { - j--; - } - while (j >= fromIndex && a[j] == 0.0d); - - // j is now one less than the index of the FIRST zero - for (int k = 0; k < numNegZeros; k++) { - a[++j] = -0.0d; - } - } - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

The {@code <} relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * {@code -0.0f == 0.0f} is {@code true} and a NaN value compares - * neither less than, greater than, nor equal to any floating-point - * value, even itself. To allow the sort to proceed, instead of using - * the {@code <} relation to determine ascending numerical order, - * this method uses the total order imposed by {@link Float#compareTo}. - * This ordering differs from the {@code <} relation in that {@code -0.0f} - * is treated as less than {@code 0.0f} and NaN is considered greater than - * any other floating-point value. For the purposes of sorting, all NaN - * values are considered equivalent and equal. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically @@ -389,93 +276,101 @@ public class Arrays { * @param a the array to be sorted */ public static void sort(float[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, * the range to be sorted is empty. * - *

The {@code <} relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * {@code -0.0f == 0.0f} is {@code true} and a NaN value compares - * neither less than, greater than, nor equal to any floating-point - * value, even itself. To allow the sort to proceed, instead of using - * the {@code <} relation to determine ascending numerical order, - * this method uses the total order imposed by {@link Float#compareTo}. - * This ordering differs from the {@code <} relation in that {@code -0.0f} - * is treated as less than {@code 0.0f} and NaN is considered greater than - * any other floating-point value. For the purposes of sorting, all NaN - * values are considered equivalent and equal. + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm * offers O(n log(n)) performance on many data sets that cause other * quicksorts to degrade to quadratic performance, and is typically * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * * @throws IllegalArgumentException if {@code fromIndex > toIndex} * @throws ArrayIndexOutOfBoundsException * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(float[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sortNegZeroAndNaN(a, fromIndex, toIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } - private static void sortNegZeroAndNaN(float[] a, int fromIndex, int toIndex) { - final int NEG_ZERO_BITS = Float.floatToIntBits(-0.0f); - /* - * The sort is done in three phases to avoid the expense of using - * NaN and -0.0f aware comparisons during the main sort. - * - * Preprocessing phase: move any NaN's to end of array, count the - * number of -0.0f's, and turn them into 0.0f's. - */ - int numNegZeros = 0; - int i = fromIndex; - int n = toIndex; - float temp; - - while (i < n) { - if (a[i] != a[i]) { - n--; - temp = a[i]; - a[i] = a[n]; - a[n] = temp; - } - else { - if (a[i] == 0 && Float.floatToIntBits(a[i]) == NEG_ZERO_BITS) { - a[i] = 0.0f; - numNegZeros++; - } - i++; - } - } - // Main sort phase: quicksort everything but the NaN's - DualPivotQuicksort.sort(a, fromIndex, n - 1); - - // Postprocessing phase: change 0.0f's to -0.0f's as required - if (numNegZeros != 0) { - int j = binarySearch0(a, fromIndex, n, 0.0f); // position of ANY zero - - do { - j--; - } - while (j >= fromIndex && a[j] == 0.0f); - - // j is now one less than the index of the FIRST zero - for (int k = 0; k < numNegZeros; k++) { - a[++j] = -0.0f; - } - } + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(double[] a) { + DualPivotQuicksort.sort(a); } + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(double[] a, int fromIndex, int toIndex) { + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /* + * Sorting of complex type arrays. + * + */ + /** * Old merge sort implementation can be selected (for * compatibility with broken comparators) using a system property. diff --git a/jdk/src/share/classes/java/util/DualPivotQuicksort.java b/jdk/src/share/classes/java/util/DualPivotQuicksort.java index be2df6e5925..d4207838bcc 100644 --- a/jdk/src/share/classes/java/util/DualPivotQuicksort.java +++ b/jdk/src/share/classes/java/util/DualPivotQuicksort.java @@ -36,11 +36,11 @@ package java.util; * @author Jon Bentley * @author Josh Bloch * - * @version 2009.10.29 m765.827.v5 + * @version 2009.11.09 m765.827.v8 */ final class DualPivotQuicksort { - // Suppresses default constructor, ensuring non-instantiability. + // Suppresses default constructor private DualPivotQuicksort() {} /* @@ -70,13 +70,43 @@ final class DualPivotQuicksort { */ /** - * Sorts the specified range of the array into ascending order. + * Sorts the specified array into ascending numerical order. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted */ - static void sort(int[] a, int left, int right) { + public static void sort(int[] a) { + doSort(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(int[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(int[] a, int left, int right) { // Use insertion sort on tiny arrays if (right - left + 1 < INSERTION_SORT_THRESHOLD) { for (int k = left + 1; k <= right; k++) { @@ -94,12 +124,12 @@ final class DualPivotQuicksort { } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted */ private static void dualPivotQuicksort(int[] a, int left, int right) { // Compute indices of five evenly spaced elements @@ -234,8 +264,8 @@ final class DualPivotQuicksort { a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -271,17 +301,47 @@ final class DualPivotQuicksort { } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + doSort(a, less, great); } /** - * Sorts the specified range of the array into ascending order. + * Sorts the specified array into ascending numerical order. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted */ - static void sort(long[] a, int left, int right) { + public static void sort(long[] a) { + doSort(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(long[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(long[] a, int left, int right) { // Use insertion sort on tiny arrays if (right - left + 1 < INSERTION_SORT_THRESHOLD) { for (int k = left + 1; k <= right; k++) { @@ -299,12 +359,12 @@ final class DualPivotQuicksort { } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted */ private static void dualPivotQuicksort(long[] a, int left, int right) { // Compute indices of five evenly spaced elements @@ -439,8 +499,8 @@ final class DualPivotQuicksort { a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -476,20 +536,50 @@ final class DualPivotQuicksort { } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + doSort(a, less, great); } - /** The number of distinct short values */ + /** + * Sorts the specified array into ascending numerical order. + * + * @param a the array to be sorted + */ + public static void sort(short[] a) { + doSort(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(short[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** The number of distinct short values. */ private static final int NUM_SHORT_VALUES = 1 << 16; /** - * Sorts the specified range of the array into ascending order. + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted */ - static void sort(short[] a, int left, int right) { + private static void doSort(short[] a, int left, int right) { // Use insertion sort on tiny arrays if (right - left + 1 < INSERTION_SORT_THRESHOLD) { for (int k = left + 1; k <= right; k++) { @@ -501,7 +591,7 @@ final class DualPivotQuicksort { } a[j + 1] = ak; } - } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + } else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { // Use counting sort on huge arrays int[] count = new int[NUM_SHORT_VALUES]; @@ -521,12 +611,12 @@ final class DualPivotQuicksort { } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted */ private static void dualPivotQuicksort(short[] a, int left, int right) { // Compute indices of five evenly spaced elements @@ -661,8 +751,8 @@ final class DualPivotQuicksort { a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -698,242 +788,50 @@ final class DualPivotQuicksort { } // Sort center part recursively, excluding known pivot values - sort(a, less, great); - } - - /** The number of distinct byte values */ - private static final int NUM_BYTE_VALUES = 1 << 8; - - /** - * Sorts the specified range of the array into ascending order. - * - * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted - */ - static void sort(byte[] a, int left, int right) { - // Use insertion sort on tiny arrays - if (right - left + 1 < INSERTION_SORT_THRESHOLD) { - for (int k = left + 1; k <= right; k++) { - byte ak = a[k]; - int j; - - for (j = k - 1; j >= left && ak < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ak; - } - } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_BYTE) { - // Use counting sort on huge arrays - int[] count = new int[NUM_BYTE_VALUES]; - - for (int i = left; i <= right; i++) { - count[a[i] - Byte.MIN_VALUE]++; - } - for (int i = 0, k = left; i < count.length && k <= right; i++) { - byte value = (byte) (i + Byte.MIN_VALUE); - - for (int s = count[i]; s > 0; s--) { - a[k++] = value; - } - } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); - } + doSort(a, less, great); } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * Sorts the specified array into ascending numerical order. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted */ - private static void dualPivotQuicksort(byte[] a, int left, int right) { - // Compute indices of five evenly spaced elements - int sixth = (right - left + 1) / 6; - int e1 = left + sixth; - int e5 = right - sixth; - int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; - - // Sort these elements in place using a 5-element sorting network - if (a[e1] > a[e2]) { byte t = a[e1]; a[e1] = a[e2]; a[e2] = t; } - if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; } - if (a[e1] > a[e3]) { byte t = a[e1]; a[e1] = a[e3]; a[e3] = t; } - if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; } - if (a[e1] > a[e4]) { byte t = a[e1]; a[e1] = a[e4]; a[e4] = t; } - if (a[e3] > a[e4]) { byte t = a[e3]; a[e3] = a[e4]; a[e4] = t; } - if (a[e2] > a[e5]) { byte t = a[e2]; a[e2] = a[e5]; a[e5] = t; } - if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; } - if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; } - - /* - * Use the second and fourth of the five sorted elements as pivots. - * These values are inexpensive approximations of the first and - * second terciles of the array. Note that pivot1 <= pivot2. - * - * The pivots are stored in local variables, and the first and - * the last of the sorted elements are moved to the locations - * formerly occupied by the pivots. When partitioning is complete, - * the pivots are swapped back into their final positions, and - * excluded from subsequent sorting. - */ - byte pivot1 = a[e2]; a[e2] = a[left]; - byte pivot2 = a[e4]; a[e4] = a[right]; - - /* - * Partitioning - * - * left part center part right part - * ------------------------------------------------------------ - * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ] - * ------------------------------------------------------------ - * ^ ^ ^ - * | | | - * less k great - */ - - // Pointers - int less = left + 1; // The index of first element of center part - int great = right - 1; // The index before first element of right part - - boolean pivotsDiffer = pivot1 != pivot2; - - if (pivotsDiffer) { - /* - * Invariants: - * all in (left, less) < pivot1 - * pivot1 <= all in [less, k) <= pivot2 - * all in (great, right) > pivot2 - * - * Pointer k is the first index of ?-part - */ - for (int k = less; k <= great; k++) { - byte ak = a[k]; - - if (ak < pivot1) { - a[k] = a[less]; - a[less++] = ak; - } else if (ak > pivot2) { - while (a[great] > pivot2 && k < great) { - great--; - } - a[k] = a[great]; - a[great--] = ak; - ak = a[k]; - - if (ak < pivot1) { - a[k] = a[less]; - a[less++] = ak; - } - } - } - } else { // Pivots are equal - /* - * Partition degenerates to the traditional 3-way - * (or "Dutch National Flag") partition: - * - * left part center part right part - * ------------------------------------------------- - * [ < pivot | == pivot | ? | > pivot ] - * ------------------------------------------------- - * - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (left, less) < pivot - * all in [less, k) == pivot - * all in (great, right) > pivot - * - * Pointer k is the first index of ?-part - */ - for (int k = less; k <= great; k++) { - byte ak = a[k]; - - if (ak == pivot1) { - continue; - } - if (ak < pivot1) { - a[k] = a[less]; - a[less++] = ak; - } else { - while (a[great] > pivot1) { - great--; - } - a[k] = a[great]; - a[great--] = ak; - ak = a[k]; - - if (ak < pivot1) { - a[k] = a[less]; - a[less++] = ak; - } - } - } - } - - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); - - /* - * If pivot1 == pivot2, all elements from center - * part are equal and, therefore, already sorted - */ - if (!pivotsDiffer) { - return; - } - - /* - * If center part is too large (comprises > 5/6 of - * the array), swap internal pivot values to ends - */ - if (less < e1 && e5 < great) { - while (a[less] == pivot1) { - less++; - } - for (int k = less + 1; k <= great; k++) { - if (a[k] == pivot1) { - a[k] = a[less]; - a[less++] = pivot1; - } - } - while (a[great] == pivot2) { - great--; - } - for (int k = great - 1; k >= less; k--) { - if (a[k] == pivot2) { - a[k] = a[great]; - a[great--] = pivot2; - } - } - } - - // Sort center part recursively, excluding known pivot values - sort(a, less, great); + public static void sort(char[] a) { + doSort(a, 0, a.length - 1); } - /** The number of distinct char values */ + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(char[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** The number of distinct char values. */ private static final int NUM_CHAR_VALUES = 1 << 16; /** - * Sorts the specified range of the array into ascending order. + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted */ - static void sort(char[] a, int left, int right) { + private static void doSort(char[] a, int left, int right) { // Use insertion sort on tiny arrays if (right - left + 1 < INSERTION_SORT_THRESHOLD) { for (int k = left + 1; k <= right; k++) { @@ -945,7 +843,7 @@ final class DualPivotQuicksort { } a[j + 1] = ak; } - } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + } else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { // Use counting sort on huge arrays int[] count = new int[NUM_CHAR_VALUES]; @@ -963,12 +861,12 @@ final class DualPivotQuicksort { } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted */ private static void dualPivotQuicksort(char[] a, int left, int right) { // Compute indices of five evenly spaced elements @@ -1103,8 +1001,8 @@ final class DualPivotQuicksort { a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -1140,17 +1038,395 @@ final class DualPivotQuicksort { } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + doSort(a, less, great); } /** - * Sorts the specified range of the array into ascending order. + * Sorts the specified array into ascending numerical order. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted */ - static void sort(float[] a, int left, int right) { + public static void sort(byte[] a) { + doSort(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(byte[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** The number of distinct byte values. */ + private static final int NUM_BYTE_VALUES = 1 << 8; + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(byte[] a, int left, int right) { + // Use insertion sort on tiny arrays + if (right - left + 1 < INSERTION_SORT_THRESHOLD) { + for (int k = left + 1; k <= right; k++) { + byte ak = a[k]; + int j; + + for (j = k - 1; j >= left && ak < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ak; + } + } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_BYTE) { + // Use counting sort on huge arrays + int[] count = new int[NUM_BYTE_VALUES]; + + for (int i = left; i <= right; i++) { + count[a[i] - Byte.MIN_VALUE]++; + } + for (int i = 0, k = left; i < count.length && k <= right; i++) { + byte value = (byte) (i + Byte.MIN_VALUE); + + for (int s = count[i]; s > 0; s--) { + a[k++] = value; + } + } + } else { // Use Dual-Pivot Quicksort on large arrays + dualPivotQuicksort(a, left, right); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void dualPivotQuicksort(byte[] a, int left, int right) { + // Compute indices of five evenly spaced elements + int sixth = (right - left + 1) / 6; + int e1 = left + sixth; + int e5 = right - sixth; + int e3 = (left + right) >>> 1; // The midpoint + int e4 = e3 + sixth; + int e2 = e3 - sixth; + + // Sort these elements in place using a 5-element sorting network + if (a[e1] > a[e2]) { byte t = a[e1]; a[e1] = a[e2]; a[e2] = t; } + if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; } + if (a[e1] > a[e3]) { byte t = a[e1]; a[e1] = a[e3]; a[e3] = t; } + if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; } + if (a[e1] > a[e4]) { byte t = a[e1]; a[e1] = a[e4]; a[e4] = t; } + if (a[e3] > a[e4]) { byte t = a[e3]; a[e3] = a[e4]; a[e4] = t; } + if (a[e2] > a[e5]) { byte t = a[e2]; a[e2] = a[e5]; a[e5] = t; } + if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; } + if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; } + + /* + * Use the second and fourth of the five sorted elements as pivots. + * These values are inexpensive approximations of the first and + * second terciles of the array. Note that pivot1 <= pivot2. + * + * The pivots are stored in local variables, and the first and + * the last of the sorted elements are moved to the locations + * formerly occupied by the pivots. When partitioning is complete, + * the pivots are swapped back into their final positions, and + * excluded from subsequent sorting. + */ + byte pivot1 = a[e2]; a[e2] = a[left]; + byte pivot2 = a[e4]; a[e4] = a[right]; + + /* + * Partitioning + * + * left part center part right part + * ------------------------------------------------------------ + * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ] + * ------------------------------------------------------------ + * ^ ^ ^ + * | | | + * less k great + */ + + // Pointers + int less = left + 1; // The index of first element of center part + int great = right - 1; // The index before first element of right part + + boolean pivotsDiffer = pivot1 != pivot2; + + if (pivotsDiffer) { + /* + * Invariants: + * all in (left, less) < pivot1 + * pivot1 <= all in [less, k) <= pivot2 + * all in (great, right) > pivot2 + * + * Pointer k is the first index of ?-part + */ + for (int k = less; k <= great; k++) { + byte ak = a[k]; + + if (ak < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } else if (ak > pivot2) { + while (a[great] > pivot2 && k < great) { + great--; + } + a[k] = a[great]; + a[great--] = ak; + ak = a[k]; + + if (ak < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } else { // Pivots are equal + /* + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") partition: + * + * left part center part right part + * ------------------------------------------------- + * [ < pivot | == pivot | ? | > pivot ] + * ------------------------------------------------- + * + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (left, less) < pivot + * all in [less, k) == pivot + * all in (great, right) > pivot + * + * Pointer k is the first index of ?-part + */ + for (int k = less; k <= great; k++) { + byte ak = a[k]; + + if (ak == pivot1) { + continue; + } + if (ak < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } else { + while (a[great] > pivot1) { + great--; + } + a[k] = a[great]; + a[great--] = ak; + ak = a[k]; + + if (ak < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivot values + doSort(a, left, less - 2); + doSort(a, great + 2, right); + + /* + * If pivot1 == pivot2, all elements from center + * part are equal and, therefore, already sorted + */ + if (!pivotsDiffer) { + return; + } + + /* + * If center part is too large (comprises > 5/6 of + * the array), swap internal pivot values to ends + */ + if (less < e1 && e5 < great) { + while (a[less] == pivot1) { + less++; + } + for (int k = less + 1; k <= great; k++) { + if (a[k] == pivot1) { + a[k] = a[less]; + a[less++] = pivot1; + } + } + while (a[great] == pivot2) { + great--; + } + for (int k = great - 1; k >= less; k--) { + if (a[k] == pivot2) { + a[k] = a[great]; + a[great--] = pivot2; + } + } + } + + // Sort center part recursively, excluding known pivot values + doSort(a, less, great); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @param a the array to be sorted + */ + public static void sort(float[] a) { + sortNegZeroAndNaN(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(float[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + sortNegZeroAndNaN(a, fromIndex, toIndex - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The + * sort is done in three phases to avoid expensive comparisons in the + * inner loop. The comparisons would be expensive due to anomalies + * associated with negative zero {@code -0.0f} and {@code Float.NaN}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void sortNegZeroAndNaN(float[] a, int left, int right) { + /* + * Phase 1: Count negative zeros and move NaNs to end of array + */ + final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f); + int numNegativeZeros = 0; + int n = right; + + for (int k = left; k <= n; k++) { + float ak = a[k]; + + if (ak == 0.0f && NEGATIVE_ZERO == Float.floatToIntBits(ak)) { + a[k] = 0.0f; + numNegativeZeros++; + } else if (ak != ak) { // i.e., ak is NaN + a[k--] = a[n]; + a[n--] = Float.NaN; + } + } + + /* + * Phase 2: Sort everything except NaNs (which are already in place) + */ + doSort(a, left, n); + + /* + * Phase 3: Turn positive zeros back into negative zeros as appropriate + */ + if (numNegativeZeros == 0) { + return; + } + + // Find first zero element + int zeroIndex = findAnyZero(a, left, n); + + for (int i = zeroIndex - 1; i >= left && a[i] == 0.0f; i--) { + zeroIndex = i; + } + + // Turn the right number of positive zeros back into negative zeros + for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) { + a[i] = -0.0f; + } + } + + /** + * Returns the index of some zero element in the specified range via + * binary search. The range is assumed to be sorted, and must contain + * at least one zero. + * + * @param a the array to be searched + * @param low the index of the first element, inclusive, to be searched + * @param high the index of the last element, inclusive, to be searched + */ + private static int findAnyZero(float[] a, int low, int high) { + while (true) { + int middle = (low + high) >>> 1; + float middleValue = a[middle]; + + if (middleValue < 0.0f) { + low = middle + 1; + } else if (middleValue > 0.0f) { + high = middle - 1; + } else { // middleValue == 0.0f + return middle; + } + } + } + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in three ways: + * {@code right} index is inclusive, it does no range checking on + * {@code left} or {@code right}, and it does not handle negative + * zeros or NaNs in the array. + * + * @param a the array to be sorted, which must not contain -0.0f or NaN + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(float[] a, int left, int right) { // Use insertion sort on tiny arrays if (right - left + 1 < INSERTION_SORT_THRESHOLD) { for (int k = left + 1; k <= right; k++) { @@ -1168,12 +1444,12 @@ final class DualPivotQuicksort { } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted */ private static void dualPivotQuicksort(float[] a, int left, int right) { // Compute indices of five evenly spaced elements @@ -1308,8 +1584,8 @@ final class DualPivotQuicksort { a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -1345,17 +1621,143 @@ final class DualPivotQuicksort { } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + doSort(a, less, great); } /** - * Sorts the specified range of the array into ascending order. + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted */ - static void sort(double[] a, int left, int right) { + public static void sort(double[] a) { + sortNegZeroAndNaN(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(double[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + sortNegZeroAndNaN(a, fromIndex, toIndex - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The + * sort is done in three phases to avoid expensive comparisons in the + * inner loop. The comparisons would be expensive due to anomalies + * associated with negative zero {@code -0.0d} and {@code Double.NaN}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void sortNegZeroAndNaN(double[] a, int left, int right) { + /* + * Phase 1: Count negative zeros and move NaNs to end of array + */ + final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d); + int numNegativeZeros = 0; + int n = right; + + for (int k = left; k <= n; k++) { + double ak = a[k]; + + if (ak == 0.0d && NEGATIVE_ZERO == Double.doubleToLongBits(ak)) { + a[k] = 0.0d; + numNegativeZeros++; + } else if (ak != ak) { // i.e., ak is NaN + a[k--] = a[n]; + a[n--] = Double.NaN; + } + } + + /* + * Phase 2: Sort everything except NaNs (which are already in place) + */ + doSort(a, left, n); + + /* + * Phase 3: Turn positive zeros back into negative zeros as appropriate + */ + if (numNegativeZeros == 0) { + return; + } + + // Find first zero element + int zeroIndex = findAnyZero(a, left, n); + + for (int i = zeroIndex - 1; i >= left && a[i] == 0.0d; i--) { + zeroIndex = i; + } + + // Turn the right number of positive zeros back into negative zeros + for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) { + a[i] = -0.0d; + } + } + + /** + * Returns the index of some zero element in the specified range via + * binary search. The range is assumed to be sorted, and must contain + * at least one zero. + * + * @param a the array to be searched + * @param low the index of the first element, inclusive, to be searched + * @param high the index of the last element, inclusive, to be searched + */ + private static int findAnyZero(double[] a, int low, int high) { + while (true) { + int middle = (low + high) >>> 1; + double middleValue = a[middle]; + + if (middleValue < 0.0d) { + low = middle + 1; + } else if (middleValue > 0.0d) { + high = middle - 1; + } else { // middleValue == 0.0d + return middle; + } + } + } + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in three ways: + * {@code right} index is inclusive, it does no range checking on + * {@code left} or {@code right}, and it does not handle negative + * zeros or NaNs in the array. + * + * @param a the array to be sorted, which must not contain -0.0d and NaN + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(double[] a, int left, int right) { // Use insertion sort on tiny arrays if (right - left + 1 < INSERTION_SORT_THRESHOLD) { for (int k = left + 1; k <= right; k++) { @@ -1373,12 +1775,12 @@ final class DualPivotQuicksort { } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted */ private static void dualPivotQuicksort(double[] a, int left, int right) { // Compute indices of five evenly spaced elements @@ -1513,8 +1915,8 @@ final class DualPivotQuicksort { a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -1550,6 +1952,23 @@ final class DualPivotQuicksort { } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + doSort(a, less, great); + } + + /** + * Checks that {@code fromIndex} and {@code toIndex} are in + * the range and throws an appropriate exception, if they aren't. + */ + private static void rangeCheck(int length, int fromIndex, int toIndex) { + if (fromIndex > toIndex) { + throw new IllegalArgumentException( + "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + } + if (fromIndex < 0) { + throw new ArrayIndexOutOfBoundsException(fromIndex); + } + if (toIndex > length) { + throw new ArrayIndexOutOfBoundsException(toIndex); + } } } diff --git a/jdk/src/share/classes/java/util/Formatter.java b/jdk/src/share/classes/java/util/Formatter.java index 027e36dcc81..59ff1da0711 100644 --- a/jdk/src/share/classes/java/util/Formatter.java +++ b/jdk/src/share/classes/java/util/Formatter.java @@ -2485,55 +2485,45 @@ public final class Formatter implements Closeable, Flushable { private static Pattern fsPattern = Pattern.compile(formatSpecifier); - // Look for format specifiers in the format string. + /** + * Finds format specifiers in the format string. + */ private FormatString[] parse(String s) { - ArrayList al = new ArrayList(); + ArrayList al = new ArrayList(); Matcher m = fsPattern.matcher(s); - int i = 0; - while (i < s.length()) { + for (int i = 0, len = s.length(); i < len; ) { if (m.find(i)) { // Anything between the start of the string and the beginning // of the format specifier is either fixed text or contains // an invalid format string. if (m.start() != i) { // Make sure we didn't miss any invalid format specifiers - checkText(s.substring(i, m.start())); + checkText(s, i, m.start()); // Assume previous characters were fixed text al.add(new FixedString(s.substring(i, m.start()))); } - // Expect 6 groups in regular expression - String[] sa = new String[6]; - for (int j = 0; j < m.groupCount(); j++) - { - sa[j] = m.group(j + 1); -// System.out.print(sa[j] + " "); - } -// System.out.println(); - al.add(new FormatSpecifier(this, sa)); + al.add(new FormatSpecifier(m)); i = m.end(); } else { // No more valid format specifiers. Check for possible invalid // format specifiers. - checkText(s.substring(i)); + checkText(s, i, len); // The rest of the string is fixed text al.add(new FixedString(s.substring(i))); break; } } -// FormatString[] fs = new FormatString[al.size()]; -// for (int j = 0; j < al.size(); j++) -// System.out.println(((FormatString) al.get(j)).toString()); - return (FormatString[]) al.toArray(new FormatString[0]); + return al.toArray(new FormatString[al.size()]); } - private void checkText(String s) { - int idx; - // If there are any '%' in the given string, we got a bad format - // specifier. - if ((idx = s.indexOf('%')) != -1) { - char c = (idx > s.length() - 2 ? '%' : s.charAt(idx + 1)); - throw new UnknownFormatConversionException(String.valueOf(c)); + private static void checkText(String s, int start, int end) { + for (int i = start; i < end; i++) { + // Any '%' found in the region starts an invalid format specifier. + if (s.charAt(i) == '%') { + char c = (i == end - 1) ? '%' : s.charAt(i + 1); + throw new UnknownFormatConversionException(String.valueOf(c)); + } } } @@ -2562,8 +2552,6 @@ public final class Formatter implements Closeable, Flushable { private boolean dt = false; private char c; - private Formatter formatter; - // cache the line separator private String ls; @@ -2650,21 +2638,22 @@ public final class Formatter implements Closeable, Flushable { return c; } - FormatSpecifier(Formatter formatter, String[] sa) { - this.formatter = formatter; - int idx = 0; + FormatSpecifier(Matcher m) { + int idx = 1; - index(sa[idx++]); - flags(sa[idx++]); - width(sa[idx++]); - precision(sa[idx++]); + index(m.group(idx++)); + flags(m.group(idx++)); + width(m.group(idx++)); + precision(m.group(idx++)); - if (sa[idx] != null) { + String tT = m.group(idx++); + if (tT != null) { dt = true; - if (sa[idx].equals("T")) + if (tT.equals("T")) f.add(Flags.UPPERCASE); } - conversion(sa[++idx]); + + conversion(m.group(idx)); if (dt) checkDateTime(); @@ -2819,9 +2808,9 @@ public final class Formatter implements Closeable, Flushable { private void printString(Object arg, Locale l) throws IOException { if (arg instanceof Formattable) { - Formatter fmt = formatter; - if (formatter.locale() != l) - fmt = new Formatter(formatter.out(), l); + Formatter fmt = Formatter.this; + if (fmt.locale() != l) + fmt = new Formatter(fmt.out(), l); ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision); } else { if (f.contains(Flags.ALTERNATE)) diff --git a/jdk/src/share/classes/java/util/HashMap.java b/jdk/src/share/classes/java/util/HashMap.java index c8b0722acb9..23209ab7779 100644 --- a/jdk/src/share/classes/java/util/HashMap.java +++ b/jdk/src/share/classes/java/util/HashMap.java @@ -448,10 +448,8 @@ public class HashMap } private void putAllForCreate(Map m) { - for (Iterator> i = m.entrySet().iterator(); i.hasNext(); ) { - Map.Entry e = i.next(); + for (Map.Entry e : m.entrySet()) putForCreate(e.getKey(), e.getValue()); - } } /** @@ -536,10 +534,8 @@ public class HashMap resize(newCapacity); } - for (Iterator> i = m.entrySet().iterator(); i.hasNext(); ) { - Map.Entry e = i.next(); + for (Map.Entry e : m.entrySet()) put(e.getKey(), e.getValue()); - } } /** diff --git a/jdk/src/share/classes/java/util/HashSet.java b/jdk/src/share/classes/java/util/HashSet.java index 54f11840a9e..a011088a6e1 100644 --- a/jdk/src/share/classes/java/util/HashSet.java +++ b/jdk/src/share/classes/java/util/HashSet.java @@ -280,8 +280,8 @@ public class HashSet s.writeInt(map.size()); // Write out all elements in the proper order. - for (Iterator i=map.keySet().iterator(); i.hasNext(); ) - s.writeObject(i.next()); + for (E e : map.keySet()) + s.writeObject(e); } /** diff --git a/jdk/src/share/classes/java/util/LinkedList.java b/jdk/src/share/classes/java/util/LinkedList.java index 6b7636c8f81..24f465179e2 100644 --- a/jdk/src/share/classes/java/util/LinkedList.java +++ b/jdk/src/share/classes/java/util/LinkedList.java @@ -26,22 +26,22 @@ package java.util; /** - * Linked list implementation of the List interface. Implements all + * Linked list implementation of the {@code List} interface. Implements all * optional list operations, and permits all elements (including - * null). In addition to implementing the List interface, - * the LinkedList class provides uniformly named methods to - * get, remove and insert an element at the + * {@code null}). In addition to implementing the {@code List} interface, + * the {@code LinkedList} class provides uniformly named methods to + * {@code get}, {@code remove} and {@code insert} an element at the * beginning and end of the list. These operations allow linked lists to be * used as a stack, {@linkplain Queue queue}, or {@linkplain Deque - * double-ended queue}.

+ * double-ended queue}. * - * The class implements the Deque interface, providing - * first-in-first-out queue operations for add, - * poll, along with other stack and deque operations.

+ *

The class implements the {@code Deque} interface, providing + * first-in-first-out queue operations for {@code add}, + * {@code poll}, along with other stack and deque operations. * - * All of the operations perform as could be expected for a doubly-linked + *

All of the operations perform as could be expected for a doubly-linked * list. Operations that index into the list will traverse the list from - * the beginning or the end, whichever is closer to the specified index.

+ * the beginning or the end, whichever is closer to the specified index. * *

Note that this implementation is not synchronized. * If multiple threads access a linked list concurrently, and at least @@ -58,11 +58,11 @@ package java.util; * unsynchronized access to the list:

  *   List list = Collections.synchronizedList(new LinkedList(...));
* - *

The iterators returned by this class's iterator and - * listIterator methods are fail-fast: if the list is + *

The iterators returned by this class's {@code iterator} and + * {@code listIterator} methods are fail-fast: if the list is * structurally modified at any time after the iterator is created, in - * any way except through the Iterator's own remove or - * add methods, the iterator will throw a {@link + * any way except through the Iterator's own {@code remove} or + * {@code add} methods, the iterator will throw a {@link * ConcurrentModificationException}. Thus, in the face of concurrent * modification, the iterator fails quickly and cleanly, rather than * risking arbitrary, non-deterministic behavior at an undetermined @@ -71,7 +71,7 @@ package java.util; *

Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: the fail-fast behavior of iterators * should be used only to detect bugs. @@ -83,7 +83,6 @@ package java.util; * @author Josh Bloch * @see List * @see ArrayList - * @see Vector * @since 1.2 * @param the type of elements held in this collection */ @@ -92,14 +91,26 @@ public class LinkedList extends AbstractSequentialList implements List, Deque, Cloneable, java.io.Serializable { - private transient Entry header = new Entry(null, null, null); - private transient int size = 0; + transient int size = 0; + + /** + * Pointer to first node. + * Invariant: (first == null && last == null) || + * (first.prev == null && first.item != null) + */ + transient Node first; + + /** + * Pointer to last node. + * Invariant: (first == null && last == null) || + * (last.next == null && last.item != null) + */ + transient Node last; /** * Constructs an empty list. */ public LinkedList() { - header.next = header.previous = header; } /** @@ -115,6 +126,119 @@ public class LinkedList addAll(c); } + /** + * Links e as first element. + */ + private void linkFirst(E e) { + final Node f = first; + final Node newNode = new Node(null, e, f); + first = newNode; + if (f == null) + last = newNode; + else + f.prev = newNode; + size++; + modCount++; + } + + /** + * Links e as last element. + */ + void linkLast(E e) { + final Node l = last; + final Node newNode = new Node(l, e, null); + last = newNode; + if (l == null) + first = newNode; + else + l.next = newNode; + size++; + modCount++; + } + + /** + * Inserts element e before non-null Node succ. + */ + void linkBefore(E e, Node succ) { + // assert succ != null; + final Node pred = succ.prev; + final Node newNode = new Node(pred, e, succ); + succ.prev = newNode; + if (pred == null) + first = newNode; + else + pred.next = newNode; + size++; + modCount++; + } + + /** + * Unlinks non-null first node f. + */ + private E unlinkFirst(Node f) { + // assert f == first && f != null; + final E element = f.item; + final Node next = f.next; + f.item = null; + f.next = null; // help GC + first = next; + if (next == null) + last = null; + else + next.prev = null; + size--; + modCount++; + return element; + } + + /** + * Unlinks non-null last node l. + */ + private E unlinkLast(Node l) { + // assert l == last && l != null; + final E element = l.item; + final Node prev = l.prev; + l.item = null; + l.prev = null; // help GC + last = prev; + if (prev == null) + first = null; + else + prev.next = null; + size--; + modCount++; + return element; + } + + /** + * Unlinks non-null node x. + */ + E unlink(Node x) { + // assert x != null; + final E element = x.item; + final Node next = x.next; + final Node prev = x.prev; + + if (prev == null) { + first = next; + } else { + prev.next = next; + x.prev = null; + } + + if (next == null) { + last = prev; + } else { + next.prev = prev; + x.next = null; + } + + x.item = null; + size--; + modCount++; + return element; + } + /** * Returns the first element in this list. * @@ -122,10 +246,10 @@ public class LinkedList * @throws NoSuchElementException if this list is empty */ public E getFirst() { - if (size==0) + final Node f = first; + if (f == null) throw new NoSuchElementException(); - - return header.next.element; + return f.item; } /** @@ -135,10 +259,10 @@ public class LinkedList * @throws NoSuchElementException if this list is empty */ public E getLast() { - if (size==0) + final Node l = last; + if (l == null) throw new NoSuchElementException(); - - return header.previous.element; + return l.item; } /** @@ -148,7 +272,10 @@ public class LinkedList * @throws NoSuchElementException if this list is empty */ public E removeFirst() { - return remove(header.next); + final Node f = first; + if (f == null) + throw new NoSuchElementException(); + return unlinkFirst(f); } /** @@ -158,7 +285,10 @@ public class LinkedList * @throws NoSuchElementException if this list is empty */ public E removeLast() { - return remove(header.previous); + final Node l = last; + if (l == null) + throw new NoSuchElementException(); + return unlinkLast(l); } /** @@ -167,7 +297,7 @@ public class LinkedList * @param e the element to add */ public void addFirst(E e) { - addBefore(e, header.next); + linkFirst(e); } /** @@ -178,17 +308,17 @@ public class LinkedList * @param e the element to add */ public void addLast(E e) { - addBefore(e, header); + linkLast(e); } /** - * Returns true if this list contains the specified element. - * More formally, returns true if and only if this list contains - * at least one element e such that + * Returns {@code true} if this list contains the specified element. + * More formally, returns {@code true} if and only if this list contains + * at least one element {@code e} such that * (o==null ? e==null : o.equals(e)). * * @param o element whose presence in this list is to be tested - * @return true if this list contains the specified element + * @return {@code true} if this list contains the specified element */ public boolean contains(Object o) { return indexOf(o) != -1; @@ -209,10 +339,10 @@ public class LinkedList *

This method is equivalent to {@link #addLast}. * * @param e element to be appended to this list - * @return true (as specified by {@link Collection#add}) + * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { - addBefore(e, header); + linkLast(e); return true; } @@ -220,27 +350,27 @@ public class LinkedList * Removes the first occurrence of the specified element from this list, * if it is present. If this list does not contain the element, it is * unchanged. More formally, removes the element with the lowest index - * i such that + * {@code i} such that * (o==null ? get(i)==null : o.equals(get(i))) - * (if such an element exists). Returns true if this list + * (if such an element exists). Returns {@code true} if this list * contained the specified element (or equivalently, if this list * changed as a result of the call). * * @param o element to be removed from this list, if present - * @return true if this list contained the specified element + * @return {@code true} if this list contained the specified element */ public boolean remove(Object o) { - if (o==null) { - for (Entry e = header.next; e != header; e = e.next) { - if (e.element==null) { - remove(e); + if (o == null) { + for (Node x = first; x != null; x = x.next) { + if (x.item == null) { + unlink(x); return true; } } } else { - for (Entry e = header.next; e != header; e = e.next) { - if (o.equals(e.element)) { - remove(e); + for (Node x = first; x != null; x = x.next) { + if (o.equals(x.item)) { + unlink(x); return true; } } @@ -257,7 +387,7 @@ public class LinkedList * this list, and it's nonempty.) * * @param c collection containing elements to be added to this list - * @return true if this list changed as a result of the call + * @return {@code true} if this list changed as a result of the call * @throws NullPointerException if the specified collection is null */ public boolean addAll(Collection c) { @@ -275,45 +405,66 @@ public class LinkedList * @param index index at which to insert the first element * from the specified collection * @param c collection containing elements to be added to this list - * @return true if this list changed as a result of the call + * @return {@code true} if this list changed as a result of the call * @throws IndexOutOfBoundsException {@inheritDoc} * @throws NullPointerException if the specified collection is null */ public boolean addAll(int index, Collection c) { - if (index < 0 || index > size) - throw new IndexOutOfBoundsException("Index: "+index+ - ", Size: "+size); + checkPositionIndex(index); + Object[] a = c.toArray(); int numNew = a.length; - if (numNew==0) + if (numNew == 0) return false; - modCount++; - Entry successor = (index==size ? header : entry(index)); - Entry predecessor = successor.previous; - for (int i=0; i e = new Entry((E)a[i], successor, predecessor); - predecessor.next = e; - predecessor = e; + Node pred, succ; + if (index == size) { + succ = null; + pred = last; + } else { + succ = node(index); + pred = succ.prev; + } + + for (Object o : a) { + @SuppressWarnings("unchecked") E e = (E) o; + Node newNode = new Node(pred, e, null); + if (pred == null) + first = newNode; + else + pred.next = newNode; + pred = newNode; + } + + if (succ == null) { + last = pred; + } else { + pred.next = succ; + succ.prev = pred; } - successor.previous = predecessor; size += numNew; + modCount++; return true; } /** * Removes all of the elements from this list. + * The list will be empty after this call returns. */ public void clear() { - Entry e = header.next; - while (e != header) { - Entry next = e.next; - e.next = e.previous = null; - e.element = null; - e = next; + // Clearing all of the links between nodes is "unnecessary", but: + // - helps a generational GC if the discarded nodes inhabit + // more than one generation + // - is sure to free memory even if there is a reachable Iterator + for (Node x = first; x != null; ) { + Node next = x.next; + x.item = null; + x.next = null; + x.prev = null; + x = next; } - header.next = header.previous = header; + first = last = null; size = 0; modCount++; } @@ -329,7 +480,8 @@ public class LinkedList * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { - return entry(index).element; + checkElementIndex(index); + return node(index).item; } /** @@ -342,9 +494,10 @@ public class LinkedList * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { - Entry e = entry(index); - E oldVal = e.element; - e.element = element; + checkElementIndex(index); + Node x = node(index); + E oldVal = x.item; + x.item = element; return oldVal; } @@ -358,7 +511,12 @@ public class LinkedList * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { - addBefore(element, (index==size ? header : entry(index))); + checkPositionIndex(index); + + if (index == size) + linkLast(element); + else + linkBefore(element, node(index)); } /** @@ -371,34 +529,69 @@ public class LinkedList * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { - return remove(entry(index)); + checkElementIndex(index); + return unlink(node(index)); } /** - * Returns the indexed entry. + * Tells if the argument is the index of an existing element. */ - private Entry entry(int index) { - if (index < 0 || index >= size) - throw new IndexOutOfBoundsException("Index: "+index+ - ", Size: "+size); - Entry e = header; - if (index < (size >> 1)) { - for (int i = 0; i <= index; i++) - e = e.next; - } else { - for (int i = size; i > index; i--) - e = e.previous; - } - return e; + private boolean isElementIndex(int index) { + return index >= 0 && index < size; } + /** + * Tells if the argument is the index of a valid position for an + * iterator or an add operation. + */ + private boolean isPositionIndex(int index) { + return index >= 0 && index <= size; + } + + /** + * Constructs an IndexOutOfBoundsException detail message. + * Of the many possible refactorings of the error handling code, + * this "outlining" performs best with both server and client VMs. + */ + private String outOfBoundsMsg(int index) { + return "Index: "+index+", Size: "+size; + } + + private void checkElementIndex(int index) { + if (!isElementIndex(index)) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + + private void checkPositionIndex(int index) { + if (!isPositionIndex(index)) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + + /** + * Returns the (non-null) Node at the specified element index. + */ + Node node(int index) { + // assert isElementIndex(index); + + if (index < (size >> 1)) { + Node x = first; + for (int i = 0; i < index; i++) + x = x.next; + return x; + } else { + Node x = last; + for (int i = size - 1; i > index; i--) + x = x.prev; + return x; + } + } // Search Operations /** * Returns the index of the first occurrence of the specified element * in this list, or -1 if this list does not contain the element. - * More formally, returns the lowest index i such that + * More formally, returns the lowest index {@code i} such that * (o==null ? get(i)==null : o.equals(get(i))), * or -1 if there is no such index. * @@ -408,15 +601,15 @@ public class LinkedList */ public int indexOf(Object o) { int index = 0; - if (o==null) { - for (Entry e = header.next; e != header; e = e.next) { - if (e.element==null) + if (o == null) { + for (Node x = first; x != null; x = x.next) { + if (x.item == null) return index; index++; } } else { - for (Entry e = header.next; e != header; e = e.next) { - if (o.equals(e.element)) + for (Node x = first; x != null; x = x.next) { + if (o.equals(x.item)) return index; index++; } @@ -427,7 +620,7 @@ public class LinkedList /** * Returns the index of the last occurrence of the specified element * in this list, or -1 if this list does not contain the element. - * More formally, returns the highest index i such that + * More formally, returns the highest index {@code i} such that * (o==null ? get(i)==null : o.equals(get(i))), * or -1 if there is no such index. * @@ -437,16 +630,16 @@ public class LinkedList */ public int lastIndexOf(Object o) { int index = size; - if (o==null) { - for (Entry e = header.previous; e != header; e = e.previous) { + if (o == null) { + for (Node x = last; x != null; x = x.prev) { index--; - if (e.element==null) + if (x.item == null) return index; } } else { - for (Entry e = header.previous; e != header; e = e.previous) { + for (Node x = last; x != null; x = x.prev) { index--; - if (o.equals(e.element)) + if (o.equals(x.item)) return index; } } @@ -457,17 +650,18 @@ public class LinkedList /** * Retrieves, but does not remove, the head (first element) of this list. - * @return the head of this list, or null if this list is empty + * + * @return the head of this list, or {@code null} if this list is empty * @since 1.5 */ public E peek() { - if (size==0) - return null; - return getFirst(); + final Node f = first; + return (f == null) ? null : f.item; } /** * Retrieves, but does not remove, the head (first element) of this list. + * * @return the head of this list * @throws NoSuchElementException if this list is empty * @since 1.5 @@ -477,14 +671,14 @@ public class LinkedList } /** - * Retrieves and removes the head (first element) of this list - * @return the head of this list, or null if this list is empty + * Retrieves and removes the head (first element) of this list. + * + * @return the head of this list, or {@code null} if this list is empty * @since 1.5 */ public E poll() { - if (size==0) - return null; - return removeFirst(); + final Node f = first; + return (f == null) ? null : unlinkFirst(f); } /** @@ -502,7 +696,7 @@ public class LinkedList * Adds the specified element as the tail (last element) of this list. * * @param e the element to add - * @return true (as specified by {@link Queue#offer}) + * @return {@code true} (as specified by {@link Queue#offer}) * @since 1.5 */ public boolean offer(E e) { @@ -514,7 +708,7 @@ public class LinkedList * Inserts the specified element at the front of this list. * * @param e the element to insert - * @return true (as specified by {@link Deque#offerFirst}) + * @return {@code true} (as specified by {@link Deque#offerFirst}) * @since 1.6 */ public boolean offerFirst(E e) { @@ -526,7 +720,7 @@ public class LinkedList * Inserts the specified element at the end of this list. * * @param e the element to insert - * @return true (as specified by {@link Deque#offerLast}) + * @return {@code true} (as specified by {@link Deque#offerLast}) * @since 1.6 */ public boolean offerLast(E e) { @@ -536,58 +730,54 @@ public class LinkedList /** * Retrieves, but does not remove, the first element of this list, - * or returns null if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the first element of this list, or null + * @return the first element of this list, or {@code null} * if this list is empty * @since 1.6 */ public E peekFirst() { - if (size==0) - return null; - return getFirst(); - } + final Node f = first; + return (f == null) ? null : f.item; + } /** * Retrieves, but does not remove, the last element of this list, - * or returns null if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the last element of this list, or null + * @return the last element of this list, or {@code null} * if this list is empty * @since 1.6 */ public E peekLast() { - if (size==0) - return null; - return getLast(); + final Node l = last; + return (l == null) ? null : l.item; } /** * Retrieves and removes the first element of this list, - * or returns null if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the first element of this list, or null if + * @return the first element of this list, or {@code null} if * this list is empty * @since 1.6 */ public E pollFirst() { - if (size==0) - return null; - return removeFirst(); + final Node f = first; + return (f == null) ? null : unlinkFirst(f); } /** * Retrieves and removes the last element of this list, - * or returns null if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the last element of this list, or null if + * @return the last element of this list, or {@code null} if * this list is empty * @since 1.6 */ public E pollLast() { - if (size==0) - return null; - return removeLast(); + final Node l = last; + return (l == null) ? null : unlinkLast(l); } /** @@ -624,7 +814,7 @@ public class LinkedList * does not contain the element, it is unchanged. * * @param o element to be removed from this list, if present - * @return true if the list contained the specified element + * @return {@code true} if the list contained the specified element * @since 1.6 */ public boolean removeFirstOccurrence(Object o) { @@ -637,21 +827,21 @@ public class LinkedList * does not contain the element, it is unchanged. * * @param o element to be removed from this list, if present - * @return true if the list contained the specified element + * @return {@code true} if the list contained the specified element * @since 1.6 */ public boolean removeLastOccurrence(Object o) { - if (o==null) { - for (Entry e = header.previous; e != header; e = e.previous) { - if (e.element==null) { - remove(e); + if (o == null) { + for (Node x = last; x != null; x = x.prev) { + if (x.item == null) { + unlink(x); return true; } } } else { - for (Entry e = header.previous; e != header; e = e.previous) { - if (o.equals(e.element)) { - remove(e); + for (Node x = last; x != null; x = x.prev) { + if (o.equals(x.item)) { + unlink(x); return true; } } @@ -662,76 +852,68 @@ public class LinkedList /** * Returns a list-iterator of the elements in this list (in proper * sequence), starting at the specified position in the list. - * Obeys the general contract of List.listIterator(int).

+ * Obeys the general contract of {@code List.listIterator(int)}.

* * The list-iterator is fail-fast: if the list is structurally * modified at any time after the Iterator is created, in any way except - * through the list-iterator's own remove or add + * through the list-iterator's own {@code remove} or {@code add} * methods, the list-iterator will throw a - * ConcurrentModificationException. Thus, in the face of + * {@code ConcurrentModificationException}. Thus, in the face of * concurrent modification, the iterator fails quickly and cleanly, rather * than risking arbitrary, non-deterministic behavior at an undetermined * time in the future. * * @param index index of the first element to be returned from the - * list-iterator (by a call to next) + * list-iterator (by a call to {@code next}) * @return a ListIterator of the elements in this list (in proper * sequence), starting at the specified position in the list * @throws IndexOutOfBoundsException {@inheritDoc} * @see List#listIterator(int) */ public ListIterator listIterator(int index) { + checkPositionIndex(index); return new ListItr(index); } private class ListItr implements ListIterator { - private Entry lastReturned = header; - private Entry next; + private Node lastReturned = null; + private Node next; private int nextIndex; private int expectedModCount = modCount; ListItr(int index) { - if (index < 0 || index > size) - throw new IndexOutOfBoundsException("Index: "+index+ - ", Size: "+size); - if (index < (size >> 1)) { - next = header.next; - for (nextIndex=0; nextIndexindex; nextIndex--) - next = next.previous; - } + // assert isPositionIndex(index); + next = (index == size) ? null : node(index); + nextIndex = index; } public boolean hasNext() { - return nextIndex != size; + return nextIndex < size; } public E next() { checkForComodification(); - if (nextIndex == size) + if (!hasNext()) throw new NoSuchElementException(); lastReturned = next; next = next.next; nextIndex++; - return lastReturned.element; + return lastReturned.item; } public boolean hasPrevious() { - return nextIndex != 0; + return nextIndex > 0; } public E previous() { - if (nextIndex == 0) + checkForComodification(); + if (!hasPrevious()) throw new NoSuchElementException(); - lastReturned = next = next.previous; + lastReturned = next = (next == null) ? last : next.prev; nextIndex--; - checkForComodification(); - return lastReturned.element; + return lastReturned.item; } public int nextIndex() { @@ -739,36 +921,38 @@ public class LinkedList } public int previousIndex() { - return nextIndex-1; + return nextIndex - 1; } public void remove() { checkForComodification(); - Entry lastNext = lastReturned.next; - try { - LinkedList.this.remove(lastReturned); - } catch (NoSuchElementException e) { + if (lastReturned == null) throw new IllegalStateException(); - } - if (next==lastReturned) + + Node lastNext = lastReturned.next; + unlink(lastReturned); + if (next == lastReturned) next = lastNext; else nextIndex--; - lastReturned = header; + lastReturned = null; expectedModCount++; } public void set(E e) { - if (lastReturned == header) + if (lastReturned == null) throw new IllegalStateException(); checkForComodification(); - lastReturned.element = e; + lastReturned.item = e; } public void add(E e) { checkForComodification(); - lastReturned = header; - addBefore(e, next); + lastReturned = null; + if (next == null) + linkLast(e); + else + linkBefore(e, next); nextIndex++; expectedModCount++; } @@ -779,41 +963,18 @@ public class LinkedList } } - private static class Entry { - E element; - Entry next; - Entry previous; + private static class Node { + E item; + Node next; + Node prev; - Entry(E element, Entry next, Entry previous) { - this.element = element; + Node(Node prev, E element, Node next) { + this.item = element; this.next = next; - this.previous = previous; + this.prev = prev; } } - private Entry addBefore(E e, Entry entry) { - Entry newEntry = new Entry(e, entry, entry.previous); - newEntry.previous.next = newEntry; - newEntry.next.previous = newEntry; - size++; - modCount++; - return newEntry; - } - - private E remove(Entry e) { - if (e == header) - throw new NoSuchElementException(); - - E result = e.element; - e.previous.next = e.next; - e.next.previous = e.previous; - e.next = e.previous = null; - e.element = null; - size--; - modCount++; - return result; - } - /** * @since 1.6 */ @@ -821,9 +982,11 @@ public class LinkedList return new DescendingIterator(); } - /** Adapter to provide descending iterators via ListItr.previous */ - private class DescendingIterator implements Iterator { - final ListItr itr = new ListItr(size()); + /** + * Adapter to provide descending iterators via ListItr.previous + */ + private class DescendingIterator implements Iterator { + private final ListItr itr = new ListItr(size()); public boolean hasNext() { return itr.hasPrevious(); } @@ -835,29 +998,32 @@ public class LinkedList } } - /** - * Returns a shallow copy of this LinkedList. (The elements - * themselves are not cloned.) - * - * @return a shallow copy of this LinkedList instance - */ - public Object clone() { - LinkedList clone = null; + @SuppressWarnings("unchecked") + private LinkedList superClone() { try { - clone = (LinkedList) super.clone(); + return (LinkedList) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } + } + + /** + * Returns a shallow copy of this {@code LinkedList}. (The elements + * themselves are not cloned.) + * + * @return a shallow copy of this {@code LinkedList} instance + */ + public Object clone() { + LinkedList clone = superClone(); // Put clone into "virgin" state - clone.header = new Entry(null, null, null); - clone.header.next = clone.header.previous = clone.header; + clone.first = clone.last = null; clone.size = 0; clone.modCount = 0; // Initialize clone with our elements - for (Entry e = header.next; e != header; e = e.next) - clone.add(e.element); + for (Node x = first; x != null; x = x.next) + clone.add(x.item); return clone; } @@ -879,8 +1045,8 @@ public class LinkedList public Object[] toArray() { Object[] result = new Object[size]; int i = 0; - for (Entry e = header.next; e != header; e = e.next) - result[i++] = e.element; + for (Node x = first; x != null; x = x.next) + result[i++] = x.item; return result; } @@ -894,7 +1060,7 @@ public class LinkedList * *

If the list fits in the specified array with room to spare (i.e., * the array has more elements than the list), the element in the array - * immediately following the end of the list is set to null. + * immediately following the end of the list is set to {@code null}. * (This is useful in determining the length of the list only if * the caller knows that the list does not contain any null elements.) * @@ -903,15 +1069,15 @@ public class LinkedList * precise control over the runtime type of the output array, and may, * under certain circumstances, be used to save allocation costs. * - *

Suppose x is a list known to contain only strings. + *

Suppose {@code x} is a list known to contain only strings. * The following code can be used to dump the list into a newly - * allocated array of String: + * allocated array of {@code String}: * *

      *     String[] y = x.toArray(new String[0]);
* - * Note that toArray(new Object[0]) is identical in function to - * toArray(). + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. * * @param a the array into which the elements of the list are to * be stored, if it is big enough; otherwise, a new array of the @@ -922,14 +1088,15 @@ public class LinkedList * this list * @throws NullPointerException if the specified array is null */ + @SuppressWarnings("unchecked") public T[] toArray(T[] a) { if (a.length < size) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size); int i = 0; Object[] result = a; - for (Entry e = header.next; e != header; e = e.next) - result[i++] = e.element; + for (Node x = first; x != null; x = x.next) + result[i++] = x.item; if (a.length > size) a[size] = null; @@ -940,8 +1107,8 @@ public class LinkedList private static final long serialVersionUID = 876323262645176354L; /** - * Save the state of this LinkedList instance to a stream (that - * is, serialize it). + * Saves the state of this {@code LinkedList} instance to a stream + * (that is, serializes it). * * @serialData The size of the list (the number of elements it * contains) is emitted (int), followed by all of its @@ -956,14 +1123,15 @@ public class LinkedList s.writeInt(size); // Write out all elements in the proper order. - for (Entry e = header.next; e != header; e = e.next) - s.writeObject(e.element); + for (Node x = first; x != null; x = x.next) + s.writeObject(x.item); } /** - * Reconstitute this LinkedList instance from a stream (that is - * deserialize it). + * Reconstitutes this {@code LinkedList} instance from a stream + * (that is, deserializes it). */ + @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden serialization magic @@ -972,12 +1140,8 @@ public class LinkedList // Read in size int size = s.readInt(); - // Initialize header - header = new Entry(null, null, null); - header.next = header.previous = header; - // Read in all elements in the proper order. - for (int i=0; i * Many applications will find the method {@link Math#random} simpler to use. * + *

Instances of {@code java.util.Random} are threadsafe. + * However, the concurrent use of the same {@code java.util.Random} + * instance across threads may encounter contention and consequent + * poor performance. Consider instead using + * {@link java.util.concurrent.ThreadLocalRandom} in multithreaded + * designs. + * + *

Instances of {@code java.util.Random} are not cryptographically + * secure. Consider instead using {@link java.security.SecureRandom} to + * get a cryptographically secure pseudo-random number generator for use + * by security-sensitive applications. + * * @author Frank Yellin * @since 1.0 */ diff --git a/jdk/src/share/classes/java/util/concurrent/ArrayBlockingQueue.java b/jdk/src/share/classes/java/util/concurrent/ArrayBlockingQueue.java index 5430a853ba6..4a51c4f50ec 100644 --- a/jdk/src/share/classes/java/util/concurrent/ArrayBlockingQueue.java +++ b/jdk/src/share/classes/java/util/concurrent/ArrayBlockingQueue.java @@ -218,8 +218,8 @@ public class ArrayBlockingQueue extends AbstractQueue if (capacity < c.size()) throw new IllegalArgumentException(); - for (Iterator it = c.iterator(); it.hasNext();) - add(it.next()); + for (E e : c) + add(e); } /** diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java index 5e31adea247..0c17903fd06 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java @@ -250,8 +250,8 @@ public class ConcurrentLinkedQueue extends AbstractQueue * of its elements are null */ public ConcurrentLinkedQueue(Collection c) { - for (Iterator it = c.iterator(); it.hasNext();) - add(it.next()); + for (E e : c) + add(e); } // Have to override just to update the javadoc diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java index 323482acb4e..fd69808d422 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java @@ -895,7 +895,7 @@ public class ConcurrentSkipListMap extends AbstractMap if (n != null) { Node f = n.next; if (n != b.next) // inconsistent read - break;; + break; Object v = n.value; if (v == null) { // n is deleted n.helpDelete(b, f); diff --git a/jdk/src/share/classes/java/util/concurrent/CountDownLatch.java b/jdk/src/share/classes/java/util/concurrent/CountDownLatch.java index 18061f821ab..41f6e48e459 100644 --- a/jdk/src/share/classes/java/util/concurrent/CountDownLatch.java +++ b/jdk/src/share/classes/java/util/concurrent/CountDownLatch.java @@ -148,7 +148,8 @@ import java.util.concurrent.atomic.*; * * * - *

Memory consistency effects: Actions in a thread prior to calling + *

Memory consistency effects: Until the count reaches + * zero, actions in a thread prior to calling * {@code countDown()} * happen-before * actions following a successful return from a corresponding diff --git a/jdk/src/share/classes/java/util/concurrent/ExecutorService.java b/jdk/src/share/classes/java/util/concurrent/ExecutorService.java index 6f1f5fa8551..3dac382a6a6 100644 --- a/jdk/src/share/classes/java/util/concurrent/ExecutorService.java +++ b/jdk/src/share/classes/java/util/concurrent/ExecutorService.java @@ -332,8 +332,8 @@ public interface ExecutorService extends Executor { * @param tasks the collection of tasks * @return the result returned by one of the tasks * @throws InterruptedException if interrupted while waiting - * @throws NullPointerException if tasks or any of its elements - * are null + * @throws NullPointerException if tasks or any element task + * subject to execution is null * @throws IllegalArgumentException if tasks is empty * @throws ExecutionException if no task successfully completes * @throws RejectedExecutionException if tasks cannot be scheduled @@ -356,8 +356,8 @@ public interface ExecutorService extends Executor { * @param unit the time unit of the timeout argument * @return the result returned by one of the tasks. * @throws InterruptedException if interrupted while waiting - * @throws NullPointerException if tasks, any of its elements, or - * unit are null + * @throws NullPointerException if tasks, or unit, or any element + * task subject to execution is null * @throws TimeoutException if the given timeout elapses before * any task successfully completes * @throws ExecutionException if no task successfully completes diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java new file mode 100644 index 00000000000..71193636463 --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java @@ -0,0 +1,1988 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * An {@link ExecutorService} for running {@link ForkJoinTask}s. + * A {@code ForkJoinPool} provides the entry point for submissions + * from non-{@code ForkJoinTask}s, as well as management and + * monitoring operations. + * + *

A {@code ForkJoinPool} differs from other kinds of {@link + * ExecutorService} mainly by virtue of employing + * work-stealing: all threads in the pool attempt to find and + * execute subtasks created by other active tasks (eventually blocking + * waiting for work if none exist). This enables efficient processing + * when most tasks spawn other subtasks (as do most {@code + * ForkJoinTask}s). A {@code ForkJoinPool} may also be used for mixed + * execution of some plain {@code Runnable}- or {@code Callable}- + * based activities along with {@code ForkJoinTask}s. When setting + * {@linkplain #setAsyncMode async mode}, a {@code ForkJoinPool} may + * also be appropriate for use with fine-grained tasks of any form + * that are never joined. Otherwise, other {@code ExecutorService} + * implementations are typically more appropriate choices. + * + *

A {@code ForkJoinPool} is constructed with a given target + * parallelism level; by default, equal to the number of available + * processors. Unless configured otherwise via {@link + * #setMaintainsParallelism}, the pool attempts to maintain this + * number of active (or available) threads by dynamically adding, + * suspending, or resuming internal worker threads, even if some tasks + * are stalled waiting to join others. However, no such adjustments + * are performed in the face of blocked IO or other unmanaged + * synchronization. The nested {@link ManagedBlocker} interface + * enables extension of the kinds of synchronization accommodated. + * The target parallelism level may also be changed dynamically + * ({@link #setParallelism}). The total number of threads may be + * limited using method {@link #setMaximumPoolSize}, in which case it + * may become possible for the activities of a pool to stall due to + * the lack of available threads to process new tasks. + * + *

In addition to execution and lifecycle control methods, this + * class provides status check methods (for example + * {@link #getStealCount}) that are intended to aid in developing, + * tuning, and monitoring fork/join applications. Also, method + * {@link #toString} returns indications of pool state in a + * convenient form for informal monitoring. + * + *

Sample Usage. Normally a single {@code ForkJoinPool} is + * used for all parallel task execution in a program or subsystem. + * Otherwise, use would not usually outweigh the construction and + * bookkeeping overhead of creating a large set of threads. For + * example, a common pool could be used for the {@code SortTasks} + * illustrated in {@link RecursiveAction}. Because {@code + * ForkJoinPool} uses threads in {@linkplain java.lang.Thread#isDaemon + * daemon} mode, there is typically no need to explicitly {@link + * #shutdown} such a pool upon program exit. + * + *

+ * static final ForkJoinPool mainPool = new ForkJoinPool();
+ * ...
+ * public void sort(long[] array) {
+ *   mainPool.invoke(new SortTask(array, 0, array.length));
+ * }
+ * 
+ * + *

Implementation notes: This implementation restricts the + * maximum number of running threads to 32767. Attempts to create + * pools with greater than the maximum number result in + * {@code IllegalArgumentException}. + * + *

This implementation rejects submitted tasks (that is, by throwing + * {@link RejectedExecutionException}) only when the pool is shut down. + * + * @since 1.7 + * @author Doug Lea + */ +public class ForkJoinPool extends AbstractExecutorService { + + /* + * See the extended comments interspersed below for design, + * rationale, and walkthroughs. + */ + + /** Mask for packing and unpacking shorts */ + private static final int shortMask = 0xffff; + + /** Max pool size -- must be a power of two minus 1 */ + private static final int MAX_THREADS = 0x7FFF; + + /** + * Factory for creating new {@link ForkJoinWorkerThread}s. + * A {@code ForkJoinWorkerThreadFactory} must be defined and used + * for {@code ForkJoinWorkerThread} subclasses that extend base + * functionality or initialize threads with different contexts. + */ + public static interface ForkJoinWorkerThreadFactory { + /** + * Returns a new worker thread operating in the given pool. + * + * @param pool the pool this thread works in + * @throws NullPointerException if the pool is null + */ + public ForkJoinWorkerThread newThread(ForkJoinPool pool); + } + + /** + * Default ForkJoinWorkerThreadFactory implementation; creates a + * new ForkJoinWorkerThread. + */ + static class DefaultForkJoinWorkerThreadFactory + implements ForkJoinWorkerThreadFactory { + public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + try { + return new ForkJoinWorkerThread(pool); + } catch (OutOfMemoryError oom) { + return null; + } + } + } + + /** + * Creates a new ForkJoinWorkerThread. This factory is used unless + * overridden in ForkJoinPool constructors. + */ + public static final ForkJoinWorkerThreadFactory + defaultForkJoinWorkerThreadFactory = + new DefaultForkJoinWorkerThreadFactory(); + + /** + * Permission required for callers of methods that may start or + * kill threads. + */ + private static final RuntimePermission modifyThreadPermission = + new RuntimePermission("modifyThread"); + + /** + * If there is a security manager, makes sure caller has + * permission to modify threads. + */ + private static void checkPermission() { + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPermission(modifyThreadPermission); + } + + /** + * Generator for assigning sequence numbers as pool names. + */ + private static final AtomicInteger poolNumberGenerator = + new AtomicInteger(); + + /** + * Array holding all worker threads in the pool. Initialized upon + * first use. Array size must be a power of two. Updates and + * replacements are protected by workerLock, but it is always kept + * in a consistent enough state to be randomly accessed without + * locking by workers performing work-stealing. + */ + volatile ForkJoinWorkerThread[] workers; + + /** + * Lock protecting access to workers. + */ + private final ReentrantLock workerLock; + + /** + * Condition for awaitTermination. + */ + private final Condition termination; + + /** + * The uncaught exception handler used when any worker + * abruptly terminates + */ + private Thread.UncaughtExceptionHandler ueh; + + /** + * Creation factory for worker threads. + */ + private final ForkJoinWorkerThreadFactory factory; + + /** + * Head of stack of threads that were created to maintain + * parallelism when other threads blocked, but have since + * suspended when the parallelism level rose. + */ + private volatile WaitQueueNode spareStack; + + /** + * Sum of per-thread steal counts, updated only when threads are + * idle or terminating. + */ + private final AtomicLong stealCount; + + /** + * Queue for external submissions. + */ + private final LinkedTransferQueue> submissionQueue; + + /** + * Head of Treiber stack for barrier sync. See below for explanation. + */ + private volatile WaitQueueNode syncStack; + + /** + * The count for event barrier + */ + private volatile long eventCount; + + /** + * Pool number, just for assigning useful names to worker threads + */ + private final int poolNumber; + + /** + * The maximum allowed pool size + */ + private volatile int maxPoolSize; + + /** + * The desired parallelism level, updated only under workerLock. + */ + private volatile int parallelism; + + /** + * True if use local fifo, not default lifo, for local polling + */ + private volatile boolean locallyFifo; + + /** + * Holds number of total (i.e., created and not yet terminated) + * and running (i.e., not blocked on joins or other managed sync) + * threads, packed into one int to ensure consistent snapshot when + * making decisions about creating and suspending spare + * threads. Updated only by CAS. Note: CASes in + * updateRunningCount and preJoin assume that running active count + * is in low word, so need to be modified if this changes. + */ + private volatile int workerCounts; + + private static int totalCountOf(int s) { return s >>> 16; } + private static int runningCountOf(int s) { return s & shortMask; } + private static int workerCountsFor(int t, int r) { return (t << 16) + r; } + + /** + * Adds delta (which may be negative) to running count. This must + * be called before (with negative arg) and after (with positive) + * any managed synchronization (i.e., mainly, joins). + * + * @param delta the number to add + */ + final void updateRunningCount(int delta) { + int s; + do {} while (!casWorkerCounts(s = workerCounts, s + delta)); + } + + /** + * Adds delta (which may be negative) to both total and running + * count. This must be called upon creation and termination of + * worker threads. + * + * @param delta the number to add + */ + private void updateWorkerCount(int delta) { + int d = delta + (delta << 16); // add to both lo and hi parts + int s; + do {} while (!casWorkerCounts(s = workerCounts, s + d)); + } + + /** + * Lifecycle control. High word contains runState, low word + * contains the number of workers that are (probably) executing + * tasks. This value is atomically incremented before a worker + * gets a task to run, and decremented when worker has no tasks + * and cannot find any. These two fields are bundled together to + * support correct termination triggering. Note: activeCount + * CAS'es cheat by assuming active count is in low word, so need + * to be modified if this changes + */ + private volatile int runControl; + + // RunState values. Order among values matters + private static final int RUNNING = 0; + private static final int SHUTDOWN = 1; + private static final int TERMINATING = 2; + private static final int TERMINATED = 3; + + private static int runStateOf(int c) { return c >>> 16; } + private static int activeCountOf(int c) { return c & shortMask; } + private static int runControlFor(int r, int a) { return (r << 16) + a; } + + /** + * Tries incrementing active count; fails on contention. + * Called by workers before/during executing tasks. + * + * @return true on success + */ + final boolean tryIncrementActiveCount() { + int c = runControl; + return casRunControl(c, c+1); + } + + /** + * Tries decrementing active count; fails on contention. + * Possibly triggers termination on success. + * Called by workers when they can't find tasks. + * + * @return true on success + */ + final boolean tryDecrementActiveCount() { + int c = runControl; + int nextc = c - 1; + if (!casRunControl(c, nextc)) + return false; + if (canTerminateOnShutdown(nextc)) + terminateOnShutdown(); + return true; + } + + /** + * Returns {@code true} if argument represents zero active count + * and nonzero runstate, which is the triggering condition for + * terminating on shutdown. + */ + private static boolean canTerminateOnShutdown(int c) { + // i.e. least bit is nonzero runState bit + return ((c & -c) >>> 16) != 0; + } + + /** + * Transition run state to at least the given state. Return true + * if not already at least given state. + */ + private boolean transitionRunStateTo(int state) { + for (;;) { + int c = runControl; + if (runStateOf(c) >= state) + return false; + if (casRunControl(c, runControlFor(state, activeCountOf(c)))) + return true; + } + } + + /** + * Controls whether to add spares to maintain parallelism + */ + private volatile boolean maintainsParallelism; + + // Constructors + + /** + * Creates a {@code ForkJoinPool} with parallelism equal to {@link + * java.lang.Runtime#availableProcessors}, and using the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}. + * + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool() { + this(Runtime.getRuntime().availableProcessors(), + defaultForkJoinWorkerThreadFactory); + } + + /** + * Creates a {@code ForkJoinPool} with the indicated parallelism + * level and using the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}. + * + * @param parallelism the parallelism level + * @throws IllegalArgumentException if parallelism less than or + * equal to zero, or greater than implementation limit + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool(int parallelism) { + this(parallelism, defaultForkJoinWorkerThreadFactory); + } + + /** + * Creates a {@code ForkJoinPool} with parallelism equal to {@link + * java.lang.Runtime#availableProcessors}, and using the given + * thread factory. + * + * @param factory the factory for creating new threads + * @throws NullPointerException if the factory is null + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool(ForkJoinWorkerThreadFactory factory) { + this(Runtime.getRuntime().availableProcessors(), factory); + } + + /** + * Creates a {@code ForkJoinPool} with the given parallelism and + * thread factory. + * + * @param parallelism the parallelism level + * @param factory the factory for creating new threads + * @throws IllegalArgumentException if parallelism less than or + * equal to zero, or greater than implementation limit + * @throws NullPointerException if the factory is null + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory) { + if (parallelism <= 0 || parallelism > MAX_THREADS) + throw new IllegalArgumentException(); + if (factory == null) + throw new NullPointerException(); + checkPermission(); + this.factory = factory; + this.parallelism = parallelism; + this.maxPoolSize = MAX_THREADS; + this.maintainsParallelism = true; + this.poolNumber = poolNumberGenerator.incrementAndGet(); + this.workerLock = new ReentrantLock(); + this.termination = workerLock.newCondition(); + this.stealCount = new AtomicLong(); + this.submissionQueue = new LinkedTransferQueue>(); + // worker array and workers are lazily constructed + } + + /** + * Creates a new worker thread using factory. + * + * @param index the index to assign worker + * @return new worker, or null if factory failed + */ + private ForkJoinWorkerThread createWorker(int index) { + Thread.UncaughtExceptionHandler h = ueh; + ForkJoinWorkerThread w = factory.newThread(this); + if (w != null) { + w.poolIndex = index; + w.setDaemon(true); + w.setAsyncMode(locallyFifo); + w.setName("ForkJoinPool-" + poolNumber + "-worker-" + index); + if (h != null) + w.setUncaughtExceptionHandler(h); + } + return w; + } + + /** + * Returns a good size for worker array given pool size. + * Currently requires size to be a power of two. + */ + private static int arraySizeFor(int poolSize) { + if (poolSize <= 1) + return 1; + // See Hackers Delight, sec 3.2 + int c = poolSize >= MAX_THREADS ? MAX_THREADS : (poolSize - 1); + c |= c >>> 1; + c |= c >>> 2; + c |= c >>> 4; + c |= c >>> 8; + c |= c >>> 16; + return c + 1; + } + + /** + * Creates or resizes array if necessary to hold newLength. + * Call only under exclusion. + * + * @return the array + */ + private ForkJoinWorkerThread[] ensureWorkerArrayCapacity(int newLength) { + ForkJoinWorkerThread[] ws = workers; + if (ws == null) + return workers = new ForkJoinWorkerThread[arraySizeFor(newLength)]; + else if (newLength > ws.length) + return workers = Arrays.copyOf(ws, arraySizeFor(newLength)); + else + return ws; + } + + /** + * Tries to shrink workers into smaller array after one or more terminate. + */ + private void tryShrinkWorkerArray() { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + int len = ws.length; + int last = len - 1; + while (last >= 0 && ws[last] == null) + --last; + int newLength = arraySizeFor(last+1); + if (newLength < len) + workers = Arrays.copyOf(ws, newLength); + } + } + + /** + * Initializes workers if necessary. + */ + final void ensureWorkerInitialization() { + ForkJoinWorkerThread[] ws = workers; + if (ws == null) { + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ws = workers; + if (ws == null) { + int ps = parallelism; + ws = ensureWorkerArrayCapacity(ps); + for (int i = 0; i < ps; ++i) { + ForkJoinWorkerThread w = createWorker(i); + if (w != null) { + ws[i] = w; + w.start(); + updateWorkerCount(1); + } + } + } + } finally { + lock.unlock(); + } + } + } + + /** + * Worker creation and startup for threads added via setParallelism. + */ + private void createAndStartAddedWorkers() { + resumeAllSpares(); // Allow spares to convert to nonspare + int ps = parallelism; + ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(ps); + int len = ws.length; + // Sweep through slots, to keep lowest indices most populated + int k = 0; + while (k < len) { + if (ws[k] != null) { + ++k; + continue; + } + int s = workerCounts; + int tc = totalCountOf(s); + int rc = runningCountOf(s); + if (rc >= ps || tc >= ps) + break; + if (casWorkerCounts (s, workerCountsFor(tc+1, rc+1))) { + ForkJoinWorkerThread w = createWorker(k); + if (w != null) { + ws[k++] = w; + w.start(); + } + else { + updateWorkerCount(-1); // back out on failed creation + break; + } + } + } + } + + // Execution methods + + /** + * Common code for execute, invoke and submit + */ + private void doSubmit(ForkJoinTask task) { + if (task == null) + throw new NullPointerException(); + if (isShutdown()) + throw new RejectedExecutionException(); + if (workers == null) + ensureWorkerInitialization(); + submissionQueue.offer(task); + signalIdleWorkers(); + } + + /** + * Performs the given task, returning its result upon completion. + * + * @param task the task + * @return the task's result + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public T invoke(ForkJoinTask task) { + doSubmit(task); + return task.join(); + } + + /** + * Arranges for (asynchronous) execution of the given task. + * + * @param task the task + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public void execute(ForkJoinTask task) { + doSubmit(task); + } + + // AbstractExecutorService methods + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public void execute(Runnable task) { + ForkJoinTask job; + if (task instanceof ForkJoinTask) // avoid re-wrap + job = (ForkJoinTask) task; + else + job = ForkJoinTask.adapt(task, null); + doSubmit(job); + } + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask submit(Callable task) { + ForkJoinTask job = ForkJoinTask.adapt(task); + doSubmit(job); + return job; + } + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask submit(Runnable task, T result) { + ForkJoinTask job = ForkJoinTask.adapt(task, result); + doSubmit(job); + return job; + } + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask submit(Runnable task) { + ForkJoinTask job; + if (task instanceof ForkJoinTask) // avoid re-wrap + job = (ForkJoinTask) task; + else + job = ForkJoinTask.adapt(task, null); + doSubmit(job); + return job; + } + + /** + * Submits a ForkJoinTask for execution. + * + * @param task the task to submit + * @return the task + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask submit(ForkJoinTask task) { + doSubmit(task); + return task; + } + + + /** + * @throws NullPointerException {@inheritDoc} + * @throws RejectedExecutionException {@inheritDoc} + */ + public List> invokeAll(Collection> tasks) { + ArrayList> forkJoinTasks = + new ArrayList>(tasks.size()); + for (Callable task : tasks) + forkJoinTasks.add(ForkJoinTask.adapt(task)); + invoke(new InvokeAll(forkJoinTasks)); + + @SuppressWarnings({"unchecked", "rawtypes"}) + List> futures = (List>) (List) forkJoinTasks; + return futures; + } + + static final class InvokeAll extends RecursiveAction { + final ArrayList> tasks; + InvokeAll(ArrayList> tasks) { this.tasks = tasks; } + public void compute() { + try { invokeAll(tasks); } + catch (Exception ignore) {} + } + private static final long serialVersionUID = -7914297376763021607L; + } + + // Configuration and status settings and queries + + /** + * Returns the factory used for constructing new workers. + * + * @return the factory used for constructing new workers + */ + public ForkJoinWorkerThreadFactory getFactory() { + return factory; + } + + /** + * Returns the handler for internal worker threads that terminate + * due to unrecoverable errors encountered while executing tasks. + * + * @return the handler, or {@code null} if none + */ + public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { + Thread.UncaughtExceptionHandler h; + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + h = ueh; + } finally { + lock.unlock(); + } + return h; + } + + /** + * Sets the handler for internal worker threads that terminate due + * to unrecoverable errors encountered while executing tasks. + * Unless set, the current default or ThreadGroup handler is used + * as handler. + * + * @param h the new handler + * @return the old handler, or {@code null} if none + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public Thread.UncaughtExceptionHandler + setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler h) { + checkPermission(); + Thread.UncaughtExceptionHandler old = null; + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + old = ueh; + ueh = h; + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread w = ws[i]; + if (w != null) + w.setUncaughtExceptionHandler(h); + } + } + } finally { + lock.unlock(); + } + return old; + } + + + /** + * Sets the target parallelism level of this pool. + * + * @param parallelism the target parallelism + * @throws IllegalArgumentException if parallelism less than or + * equal to zero or greater than maximum size bounds + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public void setParallelism(int parallelism) { + checkPermission(); + if (parallelism <= 0 || parallelism > maxPoolSize) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + if (isProcessingTasks()) { + int p = this.parallelism; + this.parallelism = parallelism; + if (parallelism > p) + createAndStartAddedWorkers(); + else + trimSpares(); + } + } finally { + lock.unlock(); + } + signalIdleWorkers(); + } + + /** + * Returns the targeted parallelism level of this pool. + * + * @return the targeted parallelism level of this pool + */ + public int getParallelism() { + return parallelism; + } + + /** + * Returns the number of worker threads that have started but not + * yet terminated. This result returned by this method may differ + * from {@link #getParallelism} when threads are created to + * maintain parallelism when others are cooperatively blocked. + * + * @return the number of worker threads + */ + public int getPoolSize() { + return totalCountOf(workerCounts); + } + + /** + * Returns the maximum number of threads allowed to exist in the + * pool. Unless set using {@link #setMaximumPoolSize}, the + * maximum is an implementation-defined value designed only to + * prevent runaway growth. + * + * @return the maximum + */ + public int getMaximumPoolSize() { + return maxPoolSize; + } + + /** + * Sets the maximum number of threads allowed to exist in the + * pool. The given value should normally be greater than or equal + * to the {@link #getParallelism parallelism} level. Setting this + * value has no effect on current pool size. It controls + * construction of new threads. + * + * @throws IllegalArgumentException if negative or greater than + * internal implementation limit + */ + public void setMaximumPoolSize(int newMax) { + if (newMax < 0 || newMax > MAX_THREADS) + throw new IllegalArgumentException(); + maxPoolSize = newMax; + } + + + /** + * Returns {@code true} if this pool dynamically maintains its + * target parallelism level. If false, new threads are added only + * to avoid possible starvation. This setting is by default true. + * + * @return {@code true} if maintains parallelism + */ + public boolean getMaintainsParallelism() { + return maintainsParallelism; + } + + /** + * Sets whether this pool dynamically maintains its target + * parallelism level. If false, new threads are added only to + * avoid possible starvation. + * + * @param enable {@code true} to maintain parallelism + */ + public void setMaintainsParallelism(boolean enable) { + maintainsParallelism = enable; + } + + /** + * Establishes local first-in-first-out scheduling mode for forked + * tasks that are never joined. This mode may be more appropriate + * than default locally stack-based mode in applications in which + * worker threads only process asynchronous tasks. This method is + * designed to be invoked only when the pool is quiescent, and + * typically only before any tasks are submitted. The effects of + * invocations at other times may be unpredictable. + * + * @param async if {@code true}, use locally FIFO scheduling + * @return the previous mode + * @see #getAsyncMode + */ + public boolean setAsyncMode(boolean async) { + boolean oldMode = locallyFifo; + locallyFifo = async; + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null) + t.setAsyncMode(async); + } + } + return oldMode; + } + + /** + * Returns {@code true} if this pool uses local first-in-first-out + * scheduling mode for forked tasks that are never joined. + * + * @return {@code true} if this pool uses async mode + * @see #setAsyncMode + */ + public boolean getAsyncMode() { + return locallyFifo; + } + + /** + * Returns an estimate of the number of worker threads that are + * not blocked waiting to join tasks or for other managed + * synchronization. + * + * @return the number of worker threads + */ + public int getRunningThreadCount() { + return runningCountOf(workerCounts); + } + + /** + * Returns an estimate of the number of threads that are currently + * stealing or executing tasks. This method may overestimate the + * number of active threads. + * + * @return the number of active threads + */ + public int getActiveThreadCount() { + return activeCountOf(runControl); + } + + /** + * Returns an estimate of the number of threads that are currently + * idle waiting for tasks. This method may underestimate the + * number of idle threads. + * + * @return the number of idle threads + */ + final int getIdleThreadCount() { + int c = runningCountOf(workerCounts) - activeCountOf(runControl); + return (c <= 0) ? 0 : c; + } + + /** + * Returns {@code true} if all worker threads are currently idle. + * An idle worker is one that cannot obtain a task to execute + * because none are available to steal from other threads, and + * there are no pending submissions to the pool. This method is + * conservative; it might not return {@code true} immediately upon + * idleness of all threads, but will eventually become true if + * threads remain inactive. + * + * @return {@code true} if all threads are currently idle + */ + public boolean isQuiescent() { + return activeCountOf(runControl) == 0; + } + + /** + * Returns an estimate of the total number of tasks stolen from + * one thread's work queue by another. The reported value + * underestimates the actual total number of steals when the pool + * is not quiescent. This value may be useful for monitoring and + * tuning fork/join programs: in general, steal counts should be + * high enough to keep threads busy, but low enough to avoid + * overhead and contention across threads. + * + * @return the number of steals + */ + public long getStealCount() { + return stealCount.get(); + } + + /** + * Accumulates steal count from a worker. + * Call only when worker known to be idle. + */ + private void updateStealCount(ForkJoinWorkerThread w) { + int sc = w.getAndClearStealCount(); + if (sc != 0) + stealCount.addAndGet(sc); + } + + /** + * Returns an estimate of the total number of tasks currently held + * in queues by worker threads (but not including tasks submitted + * to the pool that have not begun executing). This value is only + * an approximation, obtained by iterating across all threads in + * the pool. This method may be useful for tuning task + * granularities. + * + * @return the number of queued tasks + */ + public long getQueuedTaskCount() { + long count = 0; + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null) + count += t.getQueueSize(); + } + } + return count; + } + + /** + * Returns an estimate of the number of tasks submitted to this + * pool that have not yet begun executing. This method takes time + * proportional to the number of submissions. + * + * @return the number of queued submissions + */ + public int getQueuedSubmissionCount() { + return submissionQueue.size(); + } + + /** + * Returns {@code true} if there are any tasks submitted to this + * pool that have not yet begun executing. + * + * @return {@code true} if there are any queued submissions + */ + public boolean hasQueuedSubmissions() { + return !submissionQueue.isEmpty(); + } + + /** + * Removes and returns the next unexecuted submission if one is + * available. This method may be useful in extensions to this + * class that re-assign work in systems with multiple pools. + * + * @return the next submission, or {@code null} if none + */ + protected ForkJoinTask pollSubmission() { + return submissionQueue.poll(); + } + + /** + * Removes all available unexecuted submitted and forked tasks + * from scheduling queues and adds them to the given collection, + * without altering their execution status. These may include + * artificially generated or wrapped tasks. This method is + * designed to be invoked only when the pool is known to be + * quiescent. Invocations at other times may not remove all + * tasks. A failure encountered while attempting to add elements + * to collection {@code c} may result in elements being in + * neither, either or both collections when the associated + * exception is thrown. The behavior of this operation is + * undefined if the specified collection is modified while the + * operation is in progress. + * + * @param c the collection to transfer elements into + * @return the number of elements transferred + */ + protected int drainTasksTo(Collection> c) { + int n = submissionQueue.drainTo(c); + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread w = ws[i]; + if (w != null) + n += w.drainTasksTo(c); + } + } + return n; + } + + /** + * Returns a string identifying this pool, as well as its state, + * including indications of run state, parallelism level, and + * worker and task counts. + * + * @return a string identifying this pool, as well as its state + */ + public String toString() { + int ps = parallelism; + int wc = workerCounts; + int rc = runControl; + long st = getStealCount(); + long qt = getQueuedTaskCount(); + long qs = getQueuedSubmissionCount(); + return super.toString() + + "[" + runStateToString(runStateOf(rc)) + + ", parallelism = " + ps + + ", size = " + totalCountOf(wc) + + ", active = " + activeCountOf(rc) + + ", running = " + runningCountOf(wc) + + ", steals = " + st + + ", tasks = " + qt + + ", submissions = " + qs + + "]"; + } + + private static String runStateToString(int rs) { + switch(rs) { + case RUNNING: return "Running"; + case SHUTDOWN: return "Shutting down"; + case TERMINATING: return "Terminating"; + case TERMINATED: return "Terminated"; + default: throw new Error("Unknown run state"); + } + } + + // lifecycle control + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be accepted. + * Invocation has no additional effect if already shut down. + * Tasks that are in the process of being submitted concurrently + * during the course of this method may or may not be rejected. + * + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public void shutdown() { + checkPermission(); + transitionRunStateTo(SHUTDOWN); + if (canTerminateOnShutdown(runControl)) { + if (workers == null) { // shutting down before workers created + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + if (workers == null) { + terminate(); + transitionRunStateTo(TERMINATED); + termination.signalAll(); + } + } finally { + lock.unlock(); + } + } + terminateOnShutdown(); + } + } + + /** + * Attempts to cancel and/or stop all tasks, and reject all + * subsequently submitted tasks. Tasks that are in the process of + * being submitted or executed concurrently during the course of + * this method may or may not be rejected. This method cancels + * both existing and unexecuted tasks, in order to permit + * termination in the presence of task dependencies. So the method + * always returns an empty list (unlike the case for some other + * Executors). + * + * @return an empty list + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public List shutdownNow() { + checkPermission(); + terminate(); + return Collections.emptyList(); + } + + /** + * Returns {@code true} if all tasks have completed following shut down. + * + * @return {@code true} if all tasks have completed following shut down + */ + public boolean isTerminated() { + return runStateOf(runControl) == TERMINATED; + } + + /** + * Returns {@code true} if the process of termination has + * commenced but not yet completed. This method may be useful for + * debugging. A return of {@code true} reported a sufficient + * period after shutdown may indicate that submitted tasks have + * ignored or suppressed interruption, causing this executor not + * to properly terminate. + * + * @return {@code true} if terminating but not yet terminated + */ + public boolean isTerminating() { + return runStateOf(runControl) == TERMINATING; + } + + /** + * Returns {@code true} if this pool has been shut down. + * + * @return {@code true} if this pool has been shut down + */ + public boolean isShutdown() { + return runStateOf(runControl) >= SHUTDOWN; + } + + /** + * Returns true if pool is not terminating or terminated. + * Used internally to suppress execution when terminating. + */ + final boolean isProcessingTasks() { + return runStateOf(runControl) < TERMINATING; + } + + /** + * Blocks until all tasks have completed execution after a shutdown + * request, or the timeout occurs, or the current thread is + * interrupted, whichever happens first. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return {@code true} if this executor terminated and + * {@code false} if the timeout elapsed before termination + * @throws InterruptedException if interrupted while waiting + */ + public boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + for (;;) { + if (isTerminated()) + return true; + if (nanos <= 0) + return false; + nanos = termination.awaitNanos(nanos); + } + } finally { + lock.unlock(); + } + } + + // Shutdown and termination support + + /** + * Callback from terminating worker. Nulls out the corresponding + * workers slot, and if terminating, tries to terminate; else + * tries to shrink workers array. + * + * @param w the worker + */ + final void workerTerminated(ForkJoinWorkerThread w) { + updateStealCount(w); + updateWorkerCount(-1); + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + int idx = w.poolIndex; + if (idx >= 0 && idx < ws.length && ws[idx] == w) + ws[idx] = null; + if (totalCountOf(workerCounts) == 0) { + terminate(); // no-op if already terminating + transitionRunStateTo(TERMINATED); + termination.signalAll(); + } + else if (isProcessingTasks()) { + tryShrinkWorkerArray(); + tryResumeSpare(true); // allow replacement + } + } + } finally { + lock.unlock(); + } + signalIdleWorkers(); + } + + /** + * Initiates termination. + */ + private void terminate() { + if (transitionRunStateTo(TERMINATING)) { + stopAllWorkers(); + resumeAllSpares(); + signalIdleWorkers(); + cancelQueuedSubmissions(); + cancelQueuedWorkerTasks(); + interruptUnterminatedWorkers(); + signalIdleWorkers(); // resignal after interrupt + } + } + + /** + * Possibly terminates when on shutdown state. + */ + private void terminateOnShutdown() { + if (!hasQueuedSubmissions() && canTerminateOnShutdown(runControl)) + terminate(); + } + + /** + * Clears out and cancels submissions. + */ + private void cancelQueuedSubmissions() { + ForkJoinTask task; + while ((task = pollSubmission()) != null) + task.cancel(false); + } + + /** + * Cleans out worker queues. + */ + private void cancelQueuedWorkerTasks() { + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null) + t.cancelTasks(); + } + } + } finally { + lock.unlock(); + } + } + + /** + * Sets each worker's status to terminating. Requires lock to avoid + * conflicts with add/remove. + */ + private void stopAllWorkers() { + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null) + t.shutdownNow(); + } + } + } finally { + lock.unlock(); + } + } + + /** + * Interrupts all unterminated workers. This is not required for + * sake of internal control, but may help unstick user code during + * shutdown. + */ + private void interruptUnterminatedWorkers() { + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null && !t.isTerminated()) { + try { + t.interrupt(); + } catch (SecurityException ignore) { + } + } + } + } + } finally { + lock.unlock(); + } + } + + + /* + * Nodes for event barrier to manage idle threads. Queue nodes + * are basic Treiber stack nodes, also used for spare stack. + * + * The event barrier has an event count and a wait queue (actually + * a Treiber stack). Workers are enabled to look for work when + * the eventCount is incremented. If they fail to find work, they + * may wait for next count. Upon release, threads help others wake + * up. + * + * Synchronization events occur only in enough contexts to + * maintain overall liveness: + * + * - Submission of a new task to the pool + * - Resizes or other changes to the workers array + * - pool termination + * - A worker pushing a task on an empty queue + * + * The case of pushing a task occurs often enough, and is heavy + * enough compared to simple stack pushes, to require special + * handling: Method signalWork returns without advancing count if + * the queue appears to be empty. This would ordinarily result in + * races causing some queued waiters not to be woken up. To avoid + * this, the first worker enqueued in method sync (see + * syncIsReleasable) rescans for tasks after being enqueued, and + * helps signal if any are found. This works well because the + * worker has nothing better to do, and so might as well help + * alleviate the overhead and contention on the threads actually + * doing work. Also, since event counts increments on task + * availability exist to maintain liveness (rather than to force + * refreshes etc), it is OK for callers to exit early if + * contending with another signaller. + */ + static final class WaitQueueNode { + WaitQueueNode next; // only written before enqueued + volatile ForkJoinWorkerThread thread; // nulled to cancel wait + final long count; // unused for spare stack + + WaitQueueNode(long c, ForkJoinWorkerThread w) { + count = c; + thread = w; + } + + /** + * Wakes up waiter, returning false if known to already + */ + boolean signal() { + ForkJoinWorkerThread t = thread; + if (t == null) + return false; + thread = null; + LockSupport.unpark(t); + return true; + } + + /** + * Awaits release on sync. + */ + void awaitSyncRelease(ForkJoinPool p) { + while (thread != null && !p.syncIsReleasable(this)) + LockSupport.park(this); + } + + /** + * Awaits resumption as spare. + */ + void awaitSpareRelease() { + while (thread != null) { + if (!Thread.interrupted()) + LockSupport.park(this); + } + } + } + + /** + * Ensures that no thread is waiting for count to advance from the + * current value of eventCount read on entry to this method, by + * releasing waiting threads if necessary. + * + * @return the count + */ + final long ensureSync() { + long c = eventCount; + WaitQueueNode q; + while ((q = syncStack) != null && q.count < c) { + if (casBarrierStack(q, null)) { + do { + q.signal(); + } while ((q = q.next) != null); + break; + } + } + return c; + } + + /** + * Increments event count and releases waiting threads. + */ + private void signalIdleWorkers() { + long c; + do {} while (!casEventCount(c = eventCount, c+1)); + ensureSync(); + } + + /** + * Signals threads waiting to poll a task. Because method sync + * rechecks availability, it is OK to only proceed if queue + * appears to be non-empty, and OK to skip under contention to + * increment count (since some other thread succeeded). + */ + final void signalWork() { + long c; + WaitQueueNode q; + if (syncStack != null && + casEventCount(c = eventCount, c+1) && + (((q = syncStack) != null && q.count <= c) && + (!casBarrierStack(q, q.next) || !q.signal()))) + ensureSync(); + } + + /** + * Waits until event count advances from last value held by + * caller, or if excess threads, caller is resumed as spare, or + * caller or pool is terminating. Updates caller's event on exit. + * + * @param w the calling worker thread + */ + final void sync(ForkJoinWorkerThread w) { + updateStealCount(w); // Transfer w's count while it is idle + + while (!w.isShutdown() && isProcessingTasks() && !suspendIfSpare(w)) { + long prev = w.lastEventCount; + WaitQueueNode node = null; + WaitQueueNode h; + while (eventCount == prev && + ((h = syncStack) == null || h.count == prev)) { + if (node == null) + node = new WaitQueueNode(prev, w); + if (casBarrierStack(node.next = h, node)) { + node.awaitSyncRelease(this); + break; + } + } + long ec = ensureSync(); + if (ec != prev) { + w.lastEventCount = ec; + break; + } + } + } + + /** + * Returns {@code true} if worker waiting on sync can proceed: + * - on signal (thread == null) + * - on event count advance (winning race to notify vs signaller) + * - on interrupt + * - if the first queued node, we find work available + * If node was not signalled and event count not advanced on exit, + * then we also help advance event count. + * + * @return {@code true} if node can be released + */ + final boolean syncIsReleasable(WaitQueueNode node) { + long prev = node.count; + if (!Thread.interrupted() && node.thread != null && + (node.next != null || + !ForkJoinWorkerThread.hasQueuedTasks(workers)) && + eventCount == prev) + return false; + if (node.thread != null) { + node.thread = null; + long ec = eventCount; + if (prev <= ec) // help signal + casEventCount(ec, ec+1); + } + return true; + } + + /** + * Returns {@code true} if a new sync event occurred since last + * call to sync or this method, if so, updating caller's count. + */ + final boolean hasNewSyncEvent(ForkJoinWorkerThread w) { + long lc = w.lastEventCount; + long ec = ensureSync(); + if (ec == lc) + return false; + w.lastEventCount = ec; + return true; + } + + // Parallelism maintenance + + /** + * Decrements running count; if too low, adds spare. + * + * Conceptually, all we need to do here is add or resume a + * spare thread when one is about to block (and remove or + * suspend it later when unblocked -- see suspendIfSpare). + * However, implementing this idea requires coping with + * several problems: we have imperfect information about the + * states of threads. Some count updates can and usually do + * lag run state changes, despite arrangements to keep them + * accurate (for example, when possible, updating counts + * before signalling or resuming), especially when running on + * dynamic JVMs that don't optimize the infrequent paths that + * update counts. Generating too many threads can make these + * problems become worse, because excess threads are more + * likely to be context-switched with others, slowing them all + * down, especially if there is no work available, so all are + * busy scanning or idling. Also, excess spare threads can + * only be suspended or removed when they are idle, not + * immediately when they aren't needed. So adding threads will + * raise parallelism level for longer than necessary. Also, + * FJ applications often encounter highly transient peaks when + * many threads are blocked joining, but for less time than it + * takes to create or resume spares. + * + * @param joinMe if non-null, return early if done + * @param maintainParallelism if true, try to stay within + * target counts, else create only to avoid starvation + * @return true if joinMe known to be done + */ + final boolean preJoin(ForkJoinTask joinMe, + boolean maintainParallelism) { + maintainParallelism &= maintainsParallelism; // overrride + boolean dec = false; // true when running count decremented + while (spareStack == null || !tryResumeSpare(dec)) { + int counts = workerCounts; + if (dec || (dec = casWorkerCounts(counts, --counts))) { + if (!needSpare(counts, maintainParallelism)) + break; + if (joinMe.status < 0) + return true; + if (tryAddSpare(counts)) + break; + } + } + return false; + } + + /** + * Same idea as preJoin + */ + final boolean preBlock(ManagedBlocker blocker, + boolean maintainParallelism) { + maintainParallelism &= maintainsParallelism; + boolean dec = false; + while (spareStack == null || !tryResumeSpare(dec)) { + int counts = workerCounts; + if (dec || (dec = casWorkerCounts(counts, --counts))) { + if (!needSpare(counts, maintainParallelism)) + break; + if (blocker.isReleasable()) + return true; + if (tryAddSpare(counts)) + break; + } + } + return false; + } + + /** + * Returns {@code true} if a spare thread appears to be needed. + * If maintaining parallelism, returns true when the deficit in + * running threads is more than the surplus of total threads, and + * there is apparently some work to do. This self-limiting rule + * means that the more threads that have already been added, the + * less parallelism we will tolerate before adding another. + * + * @param counts current worker counts + * @param maintainParallelism try to maintain parallelism + */ + private boolean needSpare(int counts, boolean maintainParallelism) { + int ps = parallelism; + int rc = runningCountOf(counts); + int tc = totalCountOf(counts); + int runningDeficit = ps - rc; + int totalSurplus = tc - ps; + return (tc < maxPoolSize && + (rc == 0 || totalSurplus < 0 || + (maintainParallelism && + runningDeficit > totalSurplus && + ForkJoinWorkerThread.hasQueuedTasks(workers)))); + } + + /** + * Adds a spare worker if lock available and no more than the + * expected numbers of threads exist. + * + * @return true if successful + */ + private boolean tryAddSpare(int expectedCounts) { + final ReentrantLock lock = this.workerLock; + int expectedRunning = runningCountOf(expectedCounts); + int expectedTotal = totalCountOf(expectedCounts); + boolean success = false; + boolean locked = false; + // confirm counts while locking; CAS after obtaining lock + try { + for (;;) { + int s = workerCounts; + int tc = totalCountOf(s); + int rc = runningCountOf(s); + if (rc > expectedRunning || tc > expectedTotal) + break; + if (!locked && !(locked = lock.tryLock())) + break; + if (casWorkerCounts(s, workerCountsFor(tc+1, rc+1))) { + createAndStartSpare(tc); + success = true; + break; + } + } + } finally { + if (locked) + lock.unlock(); + } + return success; + } + + /** + * Adds the kth spare worker. On entry, pool counts are already + * adjusted to reflect addition. + */ + private void createAndStartSpare(int k) { + ForkJoinWorkerThread w = null; + ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(k + 1); + int len = ws.length; + // Probably, we can place at slot k. If not, find empty slot + if (k < len && ws[k] != null) { + for (k = 0; k < len && ws[k] != null; ++k) + ; + } + if (k < len && isProcessingTasks() && (w = createWorker(k)) != null) { + ws[k] = w; + w.start(); + } + else + updateWorkerCount(-1); // adjust on failure + signalIdleWorkers(); + } + + /** + * Suspends calling thread w if there are excess threads. Called + * only from sync. Spares are enqueued in a Treiber stack using + * the same WaitQueueNodes as barriers. They are resumed mainly + * in preJoin, but are also woken on pool events that require all + * threads to check run state. + * + * @param w the caller + */ + private boolean suspendIfSpare(ForkJoinWorkerThread w) { + WaitQueueNode node = null; + int s; + while (parallelism < runningCountOf(s = workerCounts)) { + if (node == null) + node = new WaitQueueNode(0, w); + if (casWorkerCounts(s, s-1)) { // representation-dependent + // push onto stack + do {} while (!casSpareStack(node.next = spareStack, node)); + // block until released by resumeSpare + node.awaitSpareRelease(); + return true; + } + } + return false; + } + + /** + * Tries to pop and resume a spare thread. + * + * @param updateCount if true, increment running count on success + * @return true if successful + */ + private boolean tryResumeSpare(boolean updateCount) { + WaitQueueNode q; + while ((q = spareStack) != null) { + if (casSpareStack(q, q.next)) { + if (updateCount) + updateRunningCount(1); + q.signal(); + return true; + } + } + return false; + } + + /** + * Pops and resumes all spare threads. Same idea as ensureSync. + * + * @return true if any spares released + */ + private boolean resumeAllSpares() { + WaitQueueNode q; + while ( (q = spareStack) != null) { + if (casSpareStack(q, null)) { + do { + updateRunningCount(1); + q.signal(); + } while ((q = q.next) != null); + return true; + } + } + return false; + } + + /** + * Pops and shuts down excessive spare threads. Call only while + * holding lock. This is not guaranteed to eliminate all excess + * threads, only those suspended as spares, which are the ones + * unlikely to be needed in the future. + */ + private void trimSpares() { + int surplus = totalCountOf(workerCounts) - parallelism; + WaitQueueNode q; + while (surplus > 0 && (q = spareStack) != null) { + if (casSpareStack(q, null)) { + do { + updateRunningCount(1); + ForkJoinWorkerThread w = q.thread; + if (w != null && surplus > 0 && + runningCountOf(workerCounts) > 0 && w.shutdown()) + --surplus; + q.signal(); + } while ((q = q.next) != null); + } + } + } + + /** + * Interface for extending managed parallelism for tasks running + * in {@link ForkJoinPool}s. + * + *

A {@code ManagedBlocker} provides two methods. + * Method {@code isReleasable} must return {@code true} if + * blocking is not necessary. Method {@code block} blocks the + * current thread if necessary (perhaps internally invoking + * {@code isReleasable} before actually blocking). + * + *

For example, here is a ManagedBlocker based on a + * ReentrantLock: + *

 {@code
+     * class ManagedLocker implements ManagedBlocker {
+     *   final ReentrantLock lock;
+     *   boolean hasLock = false;
+     *   ManagedLocker(ReentrantLock lock) { this.lock = lock; }
+     *   public boolean block() {
+     *     if (!hasLock)
+     *       lock.lock();
+     *     return true;
+     *   }
+     *   public boolean isReleasable() {
+     *     return hasLock || (hasLock = lock.tryLock());
+     *   }
+     * }}
+ */ + public static interface ManagedBlocker { + /** + * Possibly blocks the current thread, for example waiting for + * a lock or condition. + * + * @return {@code true} if no additional blocking is necessary + * (i.e., if isReleasable would return true) + * @throws InterruptedException if interrupted while waiting + * (the method is not required to do so, but is allowed to) + */ + boolean block() throws InterruptedException; + + /** + * Returns {@code true} if blocking is unnecessary. + */ + boolean isReleasable(); + } + + /** + * Blocks in accord with the given blocker. If the current thread + * is a {@link ForkJoinWorkerThread}, this method possibly + * arranges for a spare thread to be activated if necessary to + * ensure parallelism while the current thread is blocked. + * + *

If {@code maintainParallelism} is {@code true} and the pool + * supports it ({@link #getMaintainsParallelism}), this method + * attempts to maintain the pool's nominal parallelism. Otherwise + * it activates a thread only if necessary to avoid complete + * starvation. This option may be preferable when blockages use + * timeouts, or are almost always brief. + * + *

If the caller is not a {@link ForkJoinTask}, this method is + * behaviorally equivalent to + *

 {@code
+     * while (!blocker.isReleasable())
+     *   if (blocker.block())
+     *     return;
+     * }
+ * + * If the caller is a {@code ForkJoinTask}, then the pool may + * first be expanded to ensure parallelism, and later adjusted. + * + * @param blocker the blocker + * @param maintainParallelism if {@code true} and supported by + * this pool, attempt to maintain the pool's nominal parallelism; + * otherwise activate a thread only if necessary to avoid + * complete starvation. + * @throws InterruptedException if blocker.block did so + */ + public static void managedBlock(ManagedBlocker blocker, + boolean maintainParallelism) + throws InterruptedException { + Thread t = Thread.currentThread(); + ForkJoinPool pool = ((t instanceof ForkJoinWorkerThread) ? + ((ForkJoinWorkerThread) t).pool : null); + if (!blocker.isReleasable()) { + try { + if (pool == null || + !pool.preBlock(blocker, maintainParallelism)) + awaitBlocker(blocker); + } finally { + if (pool != null) + pool.updateRunningCount(1); + } + } + } + + private static void awaitBlocker(ManagedBlocker blocker) + throws InterruptedException { + do {} while (!blocker.isReleasable() && !blocker.block()); + } + + // AbstractExecutorService overrides. These rely on undocumented + // fact that ForkJoinTask.adapt returns ForkJoinTasks that also + // implement RunnableFuture. + + protected RunnableFuture newTaskFor(Runnable runnable, T value) { + return (RunnableFuture) ForkJoinTask.adapt(runnable, value); + } + + protected RunnableFuture newTaskFor(Callable callable) { + return (RunnableFuture) ForkJoinTask.adapt(callable); + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long eventCountOffset = + objectFieldOffset("eventCount", ForkJoinPool.class); + private static final long workerCountsOffset = + objectFieldOffset("workerCounts", ForkJoinPool.class); + private static final long runControlOffset = + objectFieldOffset("runControl", ForkJoinPool.class); + private static final long syncStackOffset = + objectFieldOffset("syncStack",ForkJoinPool.class); + private static final long spareStackOffset = + objectFieldOffset("spareStack", ForkJoinPool.class); + + private boolean casEventCount(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, eventCountOffset, cmp, val); + } + private boolean casWorkerCounts(int cmp, int val) { + return UNSAFE.compareAndSwapInt(this, workerCountsOffset, cmp, val); + } + private boolean casRunControl(int cmp, int val) { + return UNSAFE.compareAndSwapInt(this, runControlOffset, cmp, val); + } + private boolean casSpareStack(WaitQueueNode cmp, WaitQueueNode val) { + return UNSAFE.compareAndSwapObject(this, spareStackOffset, cmp, val); + } + private boolean casBarrierStack(WaitQueueNode cmp, WaitQueueNode val) { + return UNSAFE.compareAndSwapObject(this, syncStackOffset, cmp, val); + } + + private static long objectFieldOffset(String field, Class klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } +} diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java new file mode 100644 index 00000000000..47d083a7f7e --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java @@ -0,0 +1,1292 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.RandomAccess; +import java.util.Map; +import java.util.WeakHashMap; + +/** + * Abstract base class for tasks that run within a {@link ForkJoinPool}. + * A {@code ForkJoinTask} is a thread-like entity that is much + * lighter weight than a normal thread. Huge numbers of tasks and + * subtasks may be hosted by a small number of actual threads in a + * ForkJoinPool, at the price of some usage limitations. + * + *

A "main" {@code ForkJoinTask} begins execution when submitted + * to a {@link ForkJoinPool}. Once started, it will usually in turn + * start other subtasks. As indicated by the name of this class, + * many programs using {@code ForkJoinTask} employ only methods + * {@link #fork} and {@link #join}, or derivatives such as {@link + * #invokeAll}. However, this class also provides a number of other + * methods that can come into play in advanced usages, as well as + * extension mechanics that allow support of new forms of fork/join + * processing. + * + *

A {@code ForkJoinTask} is a lightweight form of {@link Future}. + * The efficiency of {@code ForkJoinTask}s stems from a set of + * restrictions (that are only partially statically enforceable) + * reflecting their intended use as computational tasks calculating + * pure functions or operating on purely isolated objects. The + * primary coordination mechanisms are {@link #fork}, that arranges + * asynchronous execution, and {@link #join}, that doesn't proceed + * until the task's result has been computed. Computations should + * avoid {@code synchronized} methods or blocks, and should minimize + * other blocking synchronization apart from joining other tasks or + * using synchronizers such as Phasers that are advertised to + * cooperate with fork/join scheduling. Tasks should also not perform + * blocking IO, and should ideally access variables that are + * completely independent of those accessed by other running + * tasks. Minor breaches of these restrictions, for example using + * shared output streams, may be tolerable in practice, but frequent + * use may result in poor performance, and the potential to + * indefinitely stall if the number of threads not waiting for IO or + * other external synchronization becomes exhausted. This usage + * restriction is in part enforced by not permitting checked + * exceptions such as {@code IOExceptions} to be thrown. However, + * computations may still encounter unchecked exceptions, that are + * rethrown to callers attempting to join them. These exceptions may + * additionally include {@link RejectedExecutionException} stemming + * from internal resource exhaustion, such as failure to allocate + * internal task queues. + * + *

The primary method for awaiting completion and extracting + * results of a task is {@link #join}, but there are several variants: + * The {@link Future#get} methods support interruptible and/or timed + * waits for completion and report results using {@code Future} + * conventions. Method {@link #helpJoin} enables callers to actively + * execute other tasks while awaiting joins, which is sometimes more + * efficient but only applies when all subtasks are known to be + * strictly tree-structured. Method {@link #invoke} is semantically + * equivalent to {@code fork(); join()} but always attempts to begin + * execution in the current thread. The "quiet" forms of + * these methods do not extract results or report exceptions. These + * may be useful when a set of tasks are being executed, and you need + * to delay processing of results or exceptions until all complete. + * Method {@code invokeAll} (available in multiple versions) + * performs the most common form of parallel invocation: forking a set + * of tasks and joining them all. + * + *

The execution status of tasks may be queried at several levels + * of detail: {@link #isDone} is true if a task completed in any way + * (including the case where a task was cancelled without executing); + * {@link #isCompletedNormally} is true if a task completed without + * cancellation or encountering an exception; {@link #isCancelled} is + * true if the task was cancelled (in which case {@link #getException} + * returns a {@link java.util.concurrent.CancellationException}); and + * {@link #isCompletedAbnormally} is true if a task was either + * cancelled or encountered an exception, in which case {@link + * #getException} will return either the encountered exception or + * {@link java.util.concurrent.CancellationException}. + * + *

The ForkJoinTask class is not usually directly subclassed. + * Instead, you subclass one of the abstract classes that support a + * particular style of fork/join processing, typically {@link + * RecursiveAction} for computations that do not return results, or + * {@link RecursiveTask} for those that do. Normally, a concrete + * ForkJoinTask subclass declares fields comprising its parameters, + * established in a constructor, and then defines a {@code compute} + * method that somehow uses the control methods supplied by this base + * class. While these methods have {@code public} access (to allow + * instances of different task subclasses to call each other's + * methods), some of them may only be called from within other + * ForkJoinTasks (as may be determined using method {@link + * #inForkJoinPool}). Attempts to invoke them in other contexts + * result in exceptions or errors, possibly including + * ClassCastException. + * + *

Most base support methods are {@code final}, to prevent + * overriding of implementations that are intrinsically tied to the + * underlying lightweight task scheduling framework. Developers + * creating new basic styles of fork/join processing should minimally + * implement {@code protected} methods {@link #exec}, {@link + * #setRawResult}, and {@link #getRawResult}, while also introducing + * an abstract computational method that can be implemented in its + * subclasses, possibly relying on other {@code protected} methods + * provided by this class. + * + *

ForkJoinTasks should perform relatively small amounts of + * computation. Large tasks should be split into smaller subtasks, + * usually via recursive decomposition. As a very rough rule of thumb, + * a task should perform more than 100 and less than 10000 basic + * computational steps. If tasks are too big, then parallelism cannot + * improve throughput. If too small, then memory and internal task + * maintenance overhead may overwhelm processing. + * + *

This class provides {@code adapt} methods for {@link Runnable} + * and {@link Callable}, that may be of use when mixing execution of + * {@code ForkJoinTasks} with other kinds of tasks. When all tasks + * are of this form, consider using a pool in + * {@linkplain ForkJoinPool#setAsyncMode async mode}. + * + *

ForkJoinTasks are {@code Serializable}, which enables them to be + * used in extensions such as remote execution frameworks. It is + * sensible to serialize tasks only before or after, but not during, + * execution. Serialization is not relied on during execution itself. + * + * @since 1.7 + * @author Doug Lea + */ +public abstract class ForkJoinTask implements Future, Serializable { + + /** + * Run control status bits packed into a single int to minimize + * footprint and to ensure atomicity (via CAS). Status is + * initially zero, and takes on nonnegative values until + * completed, upon which status holds COMPLETED. CANCELLED, or + * EXCEPTIONAL, which use the top 3 bits. Tasks undergoing + * blocking waits by other threads have SIGNAL_MASK bits set -- + * bit 15 for external (nonFJ) waits, and the rest a count of + * waiting FJ threads. (This representation relies on + * ForkJoinPool max thread limits). Completion of a stolen task + * with SIGNAL_MASK bits set awakens waiter via notifyAll. Even + * though suboptimal for some purposes, we use basic builtin + * wait/notify to take advantage of "monitor inflation" in JVMs + * that we would otherwise need to emulate to avoid adding further + * per-task bookkeeping overhead. Note that bits 16-28 are + * currently unused. Also value 0x80000000 is available as spare + * completion value. + */ + volatile int status; // accessed directly by pool and workers + + static final int COMPLETION_MASK = 0xe0000000; + static final int NORMAL = 0xe0000000; // == mask + static final int CANCELLED = 0xc0000000; + static final int EXCEPTIONAL = 0xa0000000; + static final int SIGNAL_MASK = 0x0000ffff; + static final int INTERNAL_SIGNAL_MASK = 0x00007fff; + static final int EXTERNAL_SIGNAL = 0x00008000; // top bit of low word + + /** + * Table of exceptions thrown by tasks, to enable reporting by + * callers. Because exceptions are rare, we don't directly keep + * them with task objects, but instead use a weak ref table. Note + * that cancellation exceptions don't appear in the table, but are + * instead recorded as status values. + * TODO: Use ConcurrentReferenceHashMap + */ + static final Map, Throwable> exceptionMap = + Collections.synchronizedMap + (new WeakHashMap, Throwable>()); + + // within-package utilities + + /** + * Gets current worker thread, or null if not a worker thread. + */ + static ForkJoinWorkerThread getWorker() { + Thread t = Thread.currentThread(); + return ((t instanceof ForkJoinWorkerThread) ? + (ForkJoinWorkerThread) t : null); + } + + final boolean casStatus(int cmp, int val) { + return UNSAFE.compareAndSwapInt(this, statusOffset, cmp, val); + } + + /** + * Workaround for not being able to rethrow unchecked exceptions. + */ + static void rethrowException(Throwable ex) { + if (ex != null) + UNSAFE.throwException(ex); + } + + // Setting completion status + + /** + * Marks completion and wakes up threads waiting to join this task. + * + * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL + */ + final void setCompletion(int completion) { + ForkJoinPool pool = getPool(); + if (pool != null) { + int s; // Clear signal bits while setting completion status + do {} while ((s = status) >= 0 && !casStatus(s, completion)); + + if ((s & SIGNAL_MASK) != 0) { + if ((s &= INTERNAL_SIGNAL_MASK) != 0) + pool.updateRunningCount(s); + synchronized (this) { notifyAll(); } + } + } + else + externallySetCompletion(completion); + } + + /** + * Version of setCompletion for non-FJ threads. Leaves signal + * bits for unblocked threads to adjust, and always notifies. + */ + private void externallySetCompletion(int completion) { + int s; + do {} while ((s = status) >= 0 && + !casStatus(s, (s & SIGNAL_MASK) | completion)); + synchronized (this) { notifyAll(); } + } + + /** + * Sets status to indicate normal completion. + */ + final void setNormalCompletion() { + // Try typical fast case -- single CAS, no signal, not already done. + // Manually expand casStatus to improve chances of inlining it + if (!UNSAFE.compareAndSwapInt(this, statusOffset, 0, NORMAL)) + setCompletion(NORMAL); + } + + // internal waiting and notification + + /** + * Performs the actual monitor wait for awaitDone. + */ + private void doAwaitDone() { + // Minimize lock bias and in/de-flation effects by maximizing + // chances of waiting inside sync + try { + while (status >= 0) + synchronized (this) { if (status >= 0) wait(); } + } catch (InterruptedException ie) { + onInterruptedWait(); + } + } + + /** + * Performs the actual timed monitor wait for awaitDone. + */ + private void doAwaitDone(long startTime, long nanos) { + synchronized (this) { + try { + while (status >= 0) { + long nt = nanos - (System.nanoTime() - startTime); + if (nt <= 0) + break; + wait(nt / 1000000, (int) (nt % 1000000)); + } + } catch (InterruptedException ie) { + onInterruptedWait(); + } + } + } + + // Awaiting completion + + /** + * Sets status to indicate there is joiner, then waits for join, + * surrounded with pool notifications. + * + * @return status upon exit + */ + private int awaitDone(ForkJoinWorkerThread w, + boolean maintainParallelism) { + ForkJoinPool pool = (w == null) ? null : w.pool; + int s; + while ((s = status) >= 0) { + if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) { + if (pool == null || !pool.preJoin(this, maintainParallelism)) + doAwaitDone(); + if (((s = status) & INTERNAL_SIGNAL_MASK) != 0) + adjustPoolCountsOnUnblock(pool); + break; + } + } + return s; + } + + /** + * Timed version of awaitDone + * + * @return status upon exit + */ + private int awaitDone(ForkJoinWorkerThread w, long nanos) { + ForkJoinPool pool = (w == null) ? null : w.pool; + int s; + while ((s = status) >= 0) { + if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) { + long startTime = System.nanoTime(); + if (pool == null || !pool.preJoin(this, false)) + doAwaitDone(startTime, nanos); + if ((s = status) >= 0) { + adjustPoolCountsOnCancelledWait(pool); + s = status; + } + if (s < 0 && (s & INTERNAL_SIGNAL_MASK) != 0) + adjustPoolCountsOnUnblock(pool); + break; + } + } + return s; + } + + /** + * Notifies pool that thread is unblocked. Called by signalled + * threads when woken by non-FJ threads (which is atypical). + */ + private void adjustPoolCountsOnUnblock(ForkJoinPool pool) { + int s; + do {} while ((s = status) < 0 && !casStatus(s, s & COMPLETION_MASK)); + if (pool != null && (s &= INTERNAL_SIGNAL_MASK) != 0) + pool.updateRunningCount(s); + } + + /** + * Notifies pool to adjust counts on cancelled or timed out wait. + */ + private void adjustPoolCountsOnCancelledWait(ForkJoinPool pool) { + if (pool != null) { + int s; + while ((s = status) >= 0 && (s & INTERNAL_SIGNAL_MASK) != 0) { + if (casStatus(s, s - 1)) { + pool.updateRunningCount(1); + break; + } + } + } + } + + /** + * Handles interruptions during waits. + */ + private void onInterruptedWait() { + ForkJoinWorkerThread w = getWorker(); + if (w == null) + Thread.currentThread().interrupt(); // re-interrupt + else if (w.isTerminating()) + cancelIgnoringExceptions(); + // else if FJworker, ignore interrupt + } + + // Recording and reporting exceptions + + private void setDoneExceptionally(Throwable rex) { + exceptionMap.put(this, rex); + setCompletion(EXCEPTIONAL); + } + + /** + * Throws the exception associated with status s. + * + * @throws the exception + */ + private void reportException(int s) { + if ((s &= COMPLETION_MASK) < NORMAL) { + if (s == CANCELLED) + throw new CancellationException(); + else + rethrowException(exceptionMap.get(this)); + } + } + + /** + * Returns result or throws exception using j.u.c.Future conventions. + * Only call when {@code isDone} known to be true or thread known + * to be interrupted. + */ + private V reportFutureResult() + throws InterruptedException, ExecutionException { + if (Thread.interrupted()) + throw new InterruptedException(); + int s = status & COMPLETION_MASK; + if (s < NORMAL) { + Throwable ex; + if (s == CANCELLED) + throw new CancellationException(); + if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) + throw new ExecutionException(ex); + } + return getRawResult(); + } + + /** + * Returns result or throws exception using j.u.c.Future conventions + * with timeouts. + */ + private V reportTimedFutureResult() + throws InterruptedException, ExecutionException, TimeoutException { + if (Thread.interrupted()) + throw new InterruptedException(); + Throwable ex; + int s = status & COMPLETION_MASK; + if (s == NORMAL) + return getRawResult(); + else if (s == CANCELLED) + throw new CancellationException(); + else if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) + throw new ExecutionException(ex); + else + throw new TimeoutException(); + } + + // internal execution methods + + /** + * Calls exec, recording completion, and rethrowing exception if + * encountered. Caller should normally check status before calling. + * + * @return true if completed normally + */ + private boolean tryExec() { + try { // try block must contain only call to exec + if (!exec()) + return false; + } catch (Throwable rex) { + setDoneExceptionally(rex); + rethrowException(rex); + return false; // not reached + } + setNormalCompletion(); + return true; + } + + /** + * Main execution method used by worker threads. Invokes + * base computation unless already complete. + */ + final void quietlyExec() { + if (status >= 0) { + try { + if (!exec()) + return; + } catch (Throwable rex) { + setDoneExceptionally(rex); + return; + } + setNormalCompletion(); + } + } + + /** + * Calls exec(), recording but not rethrowing exception. + * Caller should normally check status before calling. + * + * @return true if completed normally + */ + private boolean tryQuietlyInvoke() { + try { + if (!exec()) + return false; + } catch (Throwable rex) { + setDoneExceptionally(rex); + return false; + } + setNormalCompletion(); + return true; + } + + /** + * Cancels, ignoring any exceptions it throws. + */ + final void cancelIgnoringExceptions() { + try { + cancel(false); + } catch (Throwable ignore) { + } + } + + /** + * Main implementation of helpJoin + */ + private int busyJoin(ForkJoinWorkerThread w) { + int s; + ForkJoinTask t; + while ((s = status) >= 0 && (t = w.scanWhileJoining(this)) != null) + t.quietlyExec(); + return (s >= 0) ? awaitDone(w, false) : s; // block if no work + } + + // public methods + + /** + * Arranges to asynchronously execute this task. While it is not + * necessarily enforced, it is a usage error to fork a task more + * than once unless it has completed and been reinitialized. + * Subsequent modifications to the state of this task or any data + * it operates on are not necessarily consistently observable by + * any thread other than the one executing it unless preceded by a + * call to {@link #join} or related methods, or a call to {@link + * #isDone} returning {@code true}. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return {@code this}, to simplify usage + */ + public final ForkJoinTask fork() { + ((ForkJoinWorkerThread) Thread.currentThread()) + .pushTask(this); + return this; + } + + /** + * Returns the result of the computation when it {@link #isDone is done}. + * This method differs from {@link #get()} in that + * abnormal completion results in {@code RuntimeException} or + * {@code Error}, not {@code ExecutionException}. + * + * @return the computed result + */ + public final V join() { + ForkJoinWorkerThread w = getWorker(); + if (w == null || status < 0 || !w.unpushTask(this) || !tryExec()) + reportException(awaitDone(w, true)); + return getRawResult(); + } + + /** + * Commences performing this task, awaits its completion if + * necessary, and return its result, or throws an (unchecked) + * exception if the underlying computation did so. + * + * @return the computed result + */ + public final V invoke() { + if (status >= 0 && tryExec()) + return getRawResult(); + else + return join(); + } + + /** + * Forks the given tasks, returning when {@code isDone} holds for + * each task or an (unchecked) exception is encountered, in which + * case the exception is rethrown. If either task encounters an + * exception, the other one may be, but is not guaranteed to be, + * cancelled. If both tasks throw an exception, then this method + * throws one of them. The individual status of each task may be + * checked using {@link #getException()} and related methods. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @param t1 the first task + * @param t2 the second task + * @throws NullPointerException if any task is null + */ + public static void invokeAll(ForkJoinTask t1, ForkJoinTask t2) { + t2.fork(); + t1.invoke(); + t2.join(); + } + + /** + * Forks the given tasks, returning when {@code isDone} holds for + * each task or an (unchecked) exception is encountered, in which + * case the exception is rethrown. If any task encounters an + * exception, others may be, but are not guaranteed to be, + * cancelled. If more than one task encounters an exception, then + * this method throws any one of these exceptions. The individual + * status of each task may be checked using {@link #getException()} + * and related methods. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @param tasks the tasks + * @throws NullPointerException if any task is null + */ + public static void invokeAll(ForkJoinTask... tasks) { + Throwable ex = null; + int last = tasks.length - 1; + for (int i = last; i >= 0; --i) { + ForkJoinTask t = tasks[i]; + if (t == null) { + if (ex == null) + ex = new NullPointerException(); + } + else if (i != 0) + t.fork(); + else { + t.quietlyInvoke(); + if (ex == null) + ex = t.getException(); + } + } + for (int i = 1; i <= last; ++i) { + ForkJoinTask t = tasks[i]; + if (t != null) { + if (ex != null) + t.cancel(false); + else { + t.quietlyJoin(); + if (ex == null) + ex = t.getException(); + } + } + } + if (ex != null) + rethrowException(ex); + } + + /** + * Forks all tasks in the specified collection, returning when + * {@code isDone} holds for each task or an (unchecked) exception + * is encountered. If any task encounters an exception, others + * may be, but are not guaranteed to be, cancelled. If more than + * one task encounters an exception, then this method throws any + * one of these exceptions. The individual status of each task + * may be checked using {@link #getException()} and related + * methods. The behavior of this operation is undefined if the + * specified collection is modified while the operation is in + * progress. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @param tasks the collection of tasks + * @return the tasks argument, to simplify usage + * @throws NullPointerException if tasks or any element are null + */ + public static > Collection invokeAll(Collection tasks) { + if (!(tasks instanceof RandomAccess) || !(tasks instanceof List)) { + invokeAll(tasks.toArray(new ForkJoinTask[tasks.size()])); + return tasks; + } + @SuppressWarnings("unchecked") + List> ts = + (List>) tasks; + Throwable ex = null; + int last = ts.size() - 1; + for (int i = last; i >= 0; --i) { + ForkJoinTask t = ts.get(i); + if (t == null) { + if (ex == null) + ex = new NullPointerException(); + } + else if (i != 0) + t.fork(); + else { + t.quietlyInvoke(); + if (ex == null) + ex = t.getException(); + } + } + for (int i = 1; i <= last; ++i) { + ForkJoinTask t = ts.get(i); + if (t != null) { + if (ex != null) + t.cancel(false); + else { + t.quietlyJoin(); + if (ex == null) + ex = t.getException(); + } + } + } + if (ex != null) + rethrowException(ex); + return tasks; + } + + /** + * Attempts to cancel execution of this task. This attempt will + * fail if the task has already completed, has already been + * cancelled, or could not be cancelled for some other reason. If + * successful, and this task has not started when cancel is + * called, execution of this task is suppressed, {@link + * #isCancelled} will report true, and {@link #join} will result + * in a {@code CancellationException} being thrown. + * + *

This method may be overridden in subclasses, but if so, must + * still ensure that these minimal properties hold. In particular, + * the {@code cancel} method itself must not throw exceptions. + * + *

This method is designed to be invoked by other + * tasks. To terminate the current task, you can just return or + * throw an unchecked exception from its computation method, or + * invoke {@link #completeExceptionally}. + * + * @param mayInterruptIfRunning this value is ignored in the + * default implementation because tasks are not + * cancelled via interruption + * + * @return {@code true} if this task is now cancelled + */ + public boolean cancel(boolean mayInterruptIfRunning) { + setCompletion(CANCELLED); + return (status & COMPLETION_MASK) == CANCELLED; + } + + public final boolean isDone() { + return status < 0; + } + + public final boolean isCancelled() { + return (status & COMPLETION_MASK) == CANCELLED; + } + + /** + * Returns {@code true} if this task threw an exception or was cancelled. + * + * @return {@code true} if this task threw an exception or was cancelled + */ + public final boolean isCompletedAbnormally() { + return (status & COMPLETION_MASK) < NORMAL; + } + + /** + * Returns {@code true} if this task completed without throwing an + * exception and was not cancelled. + * + * @return {@code true} if this task completed without throwing an + * exception and was not cancelled + */ + public final boolean isCompletedNormally() { + return (status & COMPLETION_MASK) == NORMAL; + } + + /** + * Returns the exception thrown by the base computation, or a + * {@code CancellationException} if cancelled, or {@code null} if + * none or if the method has not yet completed. + * + * @return the exception, or {@code null} if none + */ + public final Throwable getException() { + int s = status & COMPLETION_MASK; + return ((s >= NORMAL) ? null : + (s == CANCELLED) ? new CancellationException() : + exceptionMap.get(this)); + } + + /** + * Completes this task abnormally, and if not already aborted or + * cancelled, causes it to throw the given exception upon + * {@code join} and related operations. This method may be used + * to induce exceptions in asynchronous tasks, or to force + * completion of tasks that would not otherwise complete. Its use + * in other situations is discouraged. This method is + * overridable, but overridden versions must invoke {@code super} + * implementation to maintain guarantees. + * + * @param ex the exception to throw. If this exception is not a + * {@code RuntimeException} or {@code Error}, the actual exception + * thrown will be a {@code RuntimeException} with cause {@code ex}. + */ + public void completeExceptionally(Throwable ex) { + setDoneExceptionally((ex instanceof RuntimeException) || + (ex instanceof Error) ? ex : + new RuntimeException(ex)); + } + + /** + * Completes this task, and if not already aborted or cancelled, + * returning a {@code null} result upon {@code join} and related + * operations. This method may be used to provide results for + * asynchronous tasks, or to provide alternative handling for + * tasks that would not otherwise complete normally. Its use in + * other situations is discouraged. This method is + * overridable, but overridden versions must invoke {@code super} + * implementation to maintain guarantees. + * + * @param value the result value for this task + */ + public void complete(V value) { + try { + setRawResult(value); + } catch (Throwable rex) { + setDoneExceptionally(rex); + return; + } + setNormalCompletion(); + } + + public final V get() throws InterruptedException, ExecutionException { + ForkJoinWorkerThread w = getWorker(); + if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke()) + awaitDone(w, true); + return reportFutureResult(); + } + + public final V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + long nanos = unit.toNanos(timeout); + ForkJoinWorkerThread w = getWorker(); + if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke()) + awaitDone(w, nanos); + return reportTimedFutureResult(); + } + + /** + * Possibly executes other tasks until this task {@link #isDone is + * done}, then returns the result of the computation. This method + * may be more efficient than {@code join}, but is only applicable + * when there are no potential dependencies between continuation + * of the current task and that of any other task that might be + * executed while helping. (This usually holds for pure + * divide-and-conquer tasks). + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the computed result + */ + public final V helpJoin() { + ForkJoinWorkerThread w = (ForkJoinWorkerThread) Thread.currentThread(); + if (status < 0 || !w.unpushTask(this) || !tryExec()) + reportException(busyJoin(w)); + return getRawResult(); + } + + /** + * Possibly executes other tasks until this task {@link #isDone is + * done}. This method may be useful when processing collections + * of tasks when some have been cancelled or otherwise known to + * have aborted. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + */ + public final void quietlyHelpJoin() { + if (status >= 0) { + ForkJoinWorkerThread w = + (ForkJoinWorkerThread) Thread.currentThread(); + if (!w.unpushTask(this) || !tryQuietlyInvoke()) + busyJoin(w); + } + } + + /** + * Joins this task, without returning its result or throwing an + * exception. This method may be useful when processing + * collections of tasks when some have been cancelled or otherwise + * known to have aborted. + */ + public final void quietlyJoin() { + if (status >= 0) { + ForkJoinWorkerThread w = getWorker(); + if (w == null || !w.unpushTask(this) || !tryQuietlyInvoke()) + awaitDone(w, true); + } + } + + /** + * Commences performing this task and awaits its completion if + * necessary, without returning its result or throwing an + * exception. This method may be useful when processing + * collections of tasks when some have been cancelled or otherwise + * known to have aborted. + */ + public final void quietlyInvoke() { + if (status >= 0 && !tryQuietlyInvoke()) + quietlyJoin(); + } + + /** + * Possibly executes tasks until the pool hosting the current task + * {@link ForkJoinPool#isQuiescent is quiescent}. This method may + * be of use in designs in which many tasks are forked, but none + * are explicitly joined, instead executing them until all are + * processed. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + */ + public static void helpQuiesce() { + ((ForkJoinWorkerThread) Thread.currentThread()) + .helpQuiescePool(); + } + + /** + * Resets the internal bookkeeping state of this task, allowing a + * subsequent {@code fork}. This method allows repeated reuse of + * this task, but only if reuse occurs when this task has either + * never been forked, or has been forked, then completed and all + * outstanding joins of this task have also completed. Effects + * under any other usage conditions are not guaranteed. + * This method may be useful when executing + * pre-constructed trees of subtasks in loops. + */ + public void reinitialize() { + if ((status & COMPLETION_MASK) == EXCEPTIONAL) + exceptionMap.remove(this); + status = 0; + } + + /** + * Returns the pool hosting the current task execution, or null + * if this task is executing outside of any ForkJoinPool. + * + * @see #inForkJoinPool + * @return the pool, or {@code null} if none + */ + public static ForkJoinPool getPool() { + Thread t = Thread.currentThread(); + return (t instanceof ForkJoinWorkerThread) ? + ((ForkJoinWorkerThread) t).pool : null; + } + + /** + * Returns {@code true} if the current thread is executing as a + * ForkJoinPool computation. + * + * @return {@code true} if the current thread is executing as a + * ForkJoinPool computation, or false otherwise + */ + public static boolean inForkJoinPool() { + return Thread.currentThread() instanceof ForkJoinWorkerThread; + } + + /** + * Tries to unschedule this task for execution. This method will + * typically succeed if this task is the most recently forked task + * by the current thread, and has not commenced executing in + * another thread. This method may be useful when arranging + * alternative local processing of tasks that could have been, but + * were not, stolen. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return {@code true} if unforked + */ + public boolean tryUnfork() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .unpushTask(this); + } + + /** + * Returns an estimate of the number of tasks that have been + * forked by the current worker thread but not yet executed. This + * value may be useful for heuristic decisions about whether to + * fork other tasks. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the number of tasks + */ + public static int getQueuedTaskCount() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .getQueueSize(); + } + + /** + * Returns an estimate of how many more locally queued tasks are + * held by the current worker thread than there are other worker + * threads that might steal them. This value may be useful for + * heuristic decisions about whether to fork other tasks. In many + * usages of ForkJoinTasks, at steady state, each worker should + * aim to maintain a small constant surplus (for example, 3) of + * tasks, and to process computations locally if this threshold is + * exceeded. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the surplus number of tasks, which may be negative + */ + public static int getSurplusQueuedTaskCount() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .getEstimatedSurplusTaskCount(); + } + + // Extension methods + + /** + * Returns the result that would be returned by {@link #join}, even + * if this task completed abnormally, or {@code null} if this task + * is not known to have been completed. This method is designed + * to aid debugging, as well as to support extensions. Its use in + * any other context is discouraged. + * + * @return the result, or {@code null} if not completed + */ + public abstract V getRawResult(); + + /** + * Forces the given value to be returned as a result. This method + * is designed to support extensions, and should not in general be + * called otherwise. + * + * @param value the value + */ + protected abstract void setRawResult(V value); + + /** + * Immediately performs the base action of this task. This method + * is designed to support extensions, and should not in general be + * called otherwise. The return value controls whether this task + * is considered to be done normally. It may return false in + * asynchronous actions that require explicit invocations of + * {@link #complete} to become joinable. It may also throw an + * (unchecked) exception to indicate abnormal exit. + * + * @return {@code true} if completed normally + */ + protected abstract boolean exec(); + + /** + * Returns, but does not unschedule or execute, a task queued by + * the current thread but not yet executed, if one is immediately + * available. There is no guarantee that this task will actually + * be polled or executed next. Conversely, this method may return + * null even if a task exists but cannot be accessed without + * contention with other threads. This method is designed + * primarily to support extensions, and is unlikely to be useful + * otherwise. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the next task, or {@code null} if none are available + */ + protected static ForkJoinTask peekNextLocalTask() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .peekTask(); + } + + /** + * Unschedules and returns, without executing, the next task + * queued by the current thread but not yet executed. This method + * is designed primarily to support extensions, and is unlikely to + * be useful otherwise. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the next task, or {@code null} if none are available + */ + protected static ForkJoinTask pollNextLocalTask() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .pollLocalTask(); + } + + /** + * Unschedules and returns, without executing, the next task + * queued by the current thread but not yet executed, if one is + * available, or if not available, a task that was forked by some + * other thread, if available. Availability may be transient, so a + * {@code null} result does not necessarily imply quiescence + * of the pool this task is operating in. This method is designed + * primarily to support extensions, and is unlikely to be useful + * otherwise. + * + *

This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return a task, or {@code null} if none are available + */ + protected static ForkJoinTask pollTask() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .pollTask(); + } + + /** + * Adaptor for Runnables. This implements RunnableFuture + * to be compliant with AbstractExecutorService constraints + * when used in ForkJoinPool. + */ + static final class AdaptedRunnable extends ForkJoinTask + implements RunnableFuture { + final Runnable runnable; + final T resultOnCompletion; + T result; + AdaptedRunnable(Runnable runnable, T result) { + if (runnable == null) throw new NullPointerException(); + this.runnable = runnable; + this.resultOnCompletion = result; + } + public T getRawResult() { return result; } + public void setRawResult(T v) { result = v; } + public boolean exec() { + runnable.run(); + result = resultOnCompletion; + return true; + } + public void run() { invoke(); } + private static final long serialVersionUID = 5232453952276885070L; + } + + /** + * Adaptor for Callables + */ + static final class AdaptedCallable extends ForkJoinTask + implements RunnableFuture { + final Callable callable; + T result; + AdaptedCallable(Callable callable) { + if (callable == null) throw new NullPointerException(); + this.callable = callable; + } + public T getRawResult() { return result; } + public void setRawResult(T v) { result = v; } + public boolean exec() { + try { + result = callable.call(); + return true; + } catch (Error err) { + throw err; + } catch (RuntimeException rex) { + throw rex; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + public void run() { invoke(); } + private static final long serialVersionUID = 2838392045355241008L; + } + + /** + * Returns a new {@code ForkJoinTask} that performs the {@code run} + * method of the given {@code Runnable} as its action, and returns + * a null result upon {@link #join}. + * + * @param runnable the runnable action + * @return the task + */ + public static ForkJoinTask adapt(Runnable runnable) { + return new AdaptedRunnable(runnable, null); + } + + /** + * Returns a new {@code ForkJoinTask} that performs the {@code run} + * method of the given {@code Runnable} as its action, and returns + * the given result upon {@link #join}. + * + * @param runnable the runnable action + * @param result the result upon completion + * @return the task + */ + public static ForkJoinTask adapt(Runnable runnable, T result) { + return new AdaptedRunnable(runnable, result); + } + + /** + * Returns a new {@code ForkJoinTask} that performs the {@code call} + * method of the given {@code Callable} as its action, and returns + * its result upon {@link #join}, translating any checked exceptions + * encountered into {@code RuntimeException}. + * + * @param callable the callable action + * @return the task + */ + public static ForkJoinTask adapt(Callable callable) { + return new AdaptedCallable(callable); + } + + // Serialization support + + private static final long serialVersionUID = -7721805057305804111L; + + /** + * Saves the state to a stream. + * + * @serialData the current run status and the exception thrown + * during execution, or {@code null} if none + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeObject(getException()); + } + + /** + * Reconstitutes the instance from a stream. + * + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + status &= ~INTERNAL_SIGNAL_MASK; // clear internal signal counts + status |= EXTERNAL_SIGNAL; // conservatively set external signal + Object ex = s.readObject(); + if (ex != null) + setDoneExceptionally((Throwable) ex); + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long statusOffset = + objectFieldOffset("status", ForkJoinTask.class); + + private static long objectFieldOffset(String field, Class klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } +} diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java new file mode 100644 index 00000000000..3cc864fb2c5 --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java @@ -0,0 +1,827 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.Collection; + +/** + * A thread managed by a {@link ForkJoinPool}. This class is + * subclassable solely for the sake of adding functionality -- there + * are no overridable methods dealing with scheduling or execution. + * However, you can override initialization and termination methods + * surrounding the main task processing loop. If you do create such a + * subclass, you will also need to supply a custom {@link + * ForkJoinPool.ForkJoinWorkerThreadFactory} to use it in a {@code + * ForkJoinPool}. + * + * @since 1.7 + * @author Doug Lea + */ +public class ForkJoinWorkerThread extends Thread { + /* + * Algorithm overview: + * + * 1. Work-Stealing: Work-stealing queues are special forms of + * Deques that support only three of the four possible + * end-operations -- push, pop, and deq (aka steal), and only do + * so under the constraints that push and pop are called only from + * the owning thread, while deq may be called from other threads. + * (If you are unfamiliar with them, you probably want to read + * Herlihy and Shavit's book "The Art of Multiprocessor + * programming", chapter 16 describing these in more detail before + * proceeding.) The main work-stealing queue design is roughly + * similar to "Dynamic Circular Work-Stealing Deque" by David + * Chase and Yossi Lev, SPAA 2005 + * (http://research.sun.com/scalable/pubs/index.html). The main + * difference ultimately stems from gc requirements that we null + * out taken slots as soon as we can, to maintain as small a + * footprint as possible even in programs generating huge numbers + * of tasks. To accomplish this, we shift the CAS arbitrating pop + * vs deq (steal) from being on the indices ("base" and "sp") to + * the slots themselves (mainly via method "casSlotNull()"). So, + * both a successful pop and deq mainly entail CAS'ing a non-null + * slot to null. Because we rely on CASes of references, we do + * not need tag bits on base or sp. They are simple ints as used + * in any circular array-based queue (see for example ArrayDeque). + * Updates to the indices must still be ordered in a way that + * guarantees that (sp - base) > 0 means the queue is empty, but + * otherwise may err on the side of possibly making the queue + * appear nonempty when a push, pop, or deq have not fully + * committed. Note that this means that the deq operation, + * considered individually, is not wait-free. One thief cannot + * successfully continue until another in-progress one (or, if + * previously empty, a push) completes. However, in the + * aggregate, we ensure at least probabilistic + * non-blockingness. If an attempted steal fails, a thief always + * chooses a different random victim target to try next. So, in + * order for one thief to progress, it suffices for any + * in-progress deq or new push on any empty queue to complete. One + * reason this works well here is that apparently-nonempty often + * means soon-to-be-stealable, which gives threads a chance to + * activate if necessary before stealing (see below). + * + * This approach also enables support for "async mode" where local + * task processing is in FIFO, not LIFO order; simply by using a + * version of deq rather than pop when locallyFifo is true (as set + * by the ForkJoinPool). This allows use in message-passing + * frameworks in which tasks are never joined. + * + * Efficient implementation of this approach currently relies on + * an uncomfortable amount of "Unsafe" mechanics. To maintain + * correct orderings, reads and writes of variable base require + * volatile ordering. Variable sp does not require volatile write + * but needs cheaper store-ordering on writes. Because they are + * protected by volatile base reads, reads of the queue array and + * its slots do not need volatile load semantics, but writes (in + * push) require store order and CASes (in pop and deq) require + * (volatile) CAS semantics. (See "Idempotent work stealing" by + * Michael, Saraswat, and Vechev, PPoPP 2009 + * http://portal.acm.org/citation.cfm?id=1504186 for an algorithm + * with similar properties, but without support for nulling + * slots.) Since these combinations aren't supported using + * ordinary volatiles, the only way to accomplish these + * efficiently is to use direct Unsafe calls. (Using external + * AtomicIntegers and AtomicReferenceArrays for the indices and + * array is significantly slower because of memory locality and + * indirection effects.) + * + * Further, performance on most platforms is very sensitive to + * placement and sizing of the (resizable) queue array. Even + * though these queues don't usually become all that big, the + * initial size must be large enough to counteract cache + * contention effects across multiple queues (especially in the + * presence of GC cardmarking). Also, to improve thread-locality, + * queues are currently initialized immediately after the thread + * gets the initial signal to start processing tasks. However, + * all queue-related methods except pushTask are written in a way + * that allows them to instead be lazily allocated and/or disposed + * of when empty. All together, these low-level implementation + * choices produce as much as a factor of 4 performance + * improvement compared to naive implementations, and enable the + * processing of billions of tasks per second, sometimes at the + * expense of ugliness. + * + * 2. Run control: The primary run control is based on a global + * counter (activeCount) held by the pool. It uses an algorithm + * similar to that in Herlihy and Shavit section 17.6 to cause + * threads to eventually block when all threads declare they are + * inactive. For this to work, threads must be declared active + * when executing tasks, and before stealing a task. They must be + * inactive before blocking on the Pool Barrier (awaiting a new + * submission or other Pool event). In between, there is some free + * play which we take advantage of to avoid contention and rapid + * flickering of the global activeCount: If inactive, we activate + * only if a victim queue appears to be nonempty (see above). + * Similarly, a thread tries to inactivate only after a full scan + * of other threads. The net effect is that contention on + * activeCount is rarely a measurable performance issue. (There + * are also a few other cases where we scan for work rather than + * retry/block upon contention.) + * + * 3. Selection control. We maintain policy of always choosing to + * run local tasks rather than stealing, and always trying to + * steal tasks before trying to run a new submission. All steals + * are currently performed in randomly-chosen deq-order. It may be + * worthwhile to bias these with locality / anti-locality + * information, but doing this well probably requires more + * lower-level information from JVMs than currently provided. + */ + + /** + * Capacity of work-stealing queue array upon initialization. + * Must be a power of two. Initial size must be at least 2, but is + * padded to minimize cache effects. + */ + private static final int INITIAL_QUEUE_CAPACITY = 1 << 13; + + /** + * Maximum work-stealing queue array size. Must be less than or + * equal to 1 << 28 to ensure lack of index wraparound. (This + * is less than usual bounds, because we need leftshift by 3 + * to be in int range). + */ + private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 28; + + /** + * The pool this thread works in. Accessed directly by ForkJoinTask. + */ + final ForkJoinPool pool; + + /** + * The work-stealing queue array. Size must be a power of two. + * Initialized when thread starts, to improve memory locality. + */ + private ForkJoinTask[] queue; + + /** + * Index (mod queue.length) of next queue slot to push to or pop + * from. It is written only by owner thread, via ordered store. + * Both sp and base are allowed to wrap around on overflow, but + * (sp - base) still estimates size. + */ + private volatile int sp; + + /** + * Index (mod queue.length) of least valid queue slot, which is + * always the next position to steal from if nonempty. + */ + private volatile int base; + + /** + * Activity status. When true, this worker is considered active. + * Must be false upon construction. It must be true when executing + * tasks, and BEFORE stealing a task. It must be false before + * calling pool.sync. + */ + private boolean active; + + /** + * Run state of this worker. Supports simple versions of the usual + * shutdown/shutdownNow control. + */ + private volatile int runState; + + /** + * Seed for random number generator for choosing steal victims. + * Uses Marsaglia xorshift. Must be nonzero upon initialization. + */ + private int seed; + + /** + * Number of steals, transferred to pool when idle + */ + private int stealCount; + + /** + * Index of this worker in pool array. Set once by pool before + * running, and accessed directly by pool during cleanup etc. + */ + int poolIndex; + + /** + * The last barrier event waited for. Accessed in pool callback + * methods, but only by current thread. + */ + long lastEventCount; + + /** + * True if use local fifo, not default lifo, for local polling + */ + private boolean locallyFifo; + + /** + * Creates a ForkJoinWorkerThread operating in the given pool. + * + * @param pool the pool this thread works in + * @throws NullPointerException if pool is null + */ + protected ForkJoinWorkerThread(ForkJoinPool pool) { + if (pool == null) throw new NullPointerException(); + this.pool = pool; + // Note: poolIndex is set by pool during construction + // Remaining initialization is deferred to onStart + } + + // Public access methods + + /** + * Returns the pool hosting this thread. + * + * @return the pool + */ + public ForkJoinPool getPool() { + return pool; + } + + /** + * Returns the index number of this thread in its pool. The + * returned value ranges from zero to the maximum number of + * threads (minus one) that have ever been created in the pool. + * This method may be useful for applications that track status or + * collect results per-worker rather than per-task. + * + * @return the index number + */ + public int getPoolIndex() { + return poolIndex; + } + + /** + * Establishes local first-in-first-out scheduling mode for forked + * tasks that are never joined. + * + * @param async if true, use locally FIFO scheduling + */ + void setAsyncMode(boolean async) { + locallyFifo = async; + } + + // Runstate management + + // Runstate values. Order matters + private static final int RUNNING = 0; + private static final int SHUTDOWN = 1; + private static final int TERMINATING = 2; + private static final int TERMINATED = 3; + + final boolean isShutdown() { return runState >= SHUTDOWN; } + final boolean isTerminating() { return runState >= TERMINATING; } + final boolean isTerminated() { return runState == TERMINATED; } + final boolean shutdown() { return transitionRunStateTo(SHUTDOWN); } + final boolean shutdownNow() { return transitionRunStateTo(TERMINATING); } + + /** + * Transitions to at least the given state. + * + * @return {@code true} if not already at least at given state + */ + private boolean transitionRunStateTo(int state) { + for (;;) { + int s = runState; + if (s >= state) + return false; + if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, state)) + return true; + } + } + + /** + * Tries to set status to active; fails on contention. + */ + private boolean tryActivate() { + if (!active) { + if (!pool.tryIncrementActiveCount()) + return false; + active = true; + } + return true; + } + + /** + * Tries to set status to inactive; fails on contention. + */ + private boolean tryInactivate() { + if (active) { + if (!pool.tryDecrementActiveCount()) + return false; + active = false; + } + return true; + } + + /** + * Computes next value for random victim probe. Scans don't + * require a very high quality generator, but also not a crummy + * one. Marsaglia xor-shift is cheap and works well. + */ + private static int xorShift(int r) { + r ^= (r << 13); + r ^= (r >>> 17); + return r ^ (r << 5); + } + + // Lifecycle methods + + /** + * This method is required to be public, but should never be + * called explicitly. It performs the main run loop to execute + * ForkJoinTasks. + */ + public void run() { + Throwable exception = null; + try { + onStart(); + pool.sync(this); // await first pool event + mainLoop(); + } catch (Throwable ex) { + exception = ex; + } finally { + onTermination(exception); + } + } + + /** + * Executes tasks until shut down. + */ + private void mainLoop() { + while (!isShutdown()) { + ForkJoinTask t = pollTask(); + if (t != null || (t = pollSubmission()) != null) + t.quietlyExec(); + else if (tryInactivate()) + pool.sync(this); + } + } + + /** + * Initializes internal state after construction but before + * processing any tasks. If you override this method, you must + * invoke super.onStart() at the beginning of the method. + * Initialization requires care: Most fields must have legal + * default values, to ensure that attempted accesses from other + * threads work correctly even before this thread starts + * processing tasks. + */ + protected void onStart() { + // Allocate while starting to improve chances of thread-local + // isolation + queue = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; + // Initial value of seed need not be especially random but + // should differ across workers and must be nonzero + int p = poolIndex + 1; + seed = p + (p << 8) + (p << 16) + (p << 24); // spread bits + } + + /** + * Performs cleanup associated with termination of this worker + * thread. If you override this method, you must invoke + * {@code super.onTermination} at the end of the overridden method. + * + * @param exception the exception causing this thread to abort due + * to an unrecoverable error, or {@code null} if completed normally + */ + protected void onTermination(Throwable exception) { + // Execute remaining local tasks unless aborting or terminating + while (exception == null && pool.isProcessingTasks() && base != sp) { + try { + ForkJoinTask t = popTask(); + if (t != null) + t.quietlyExec(); + } catch (Throwable ex) { + exception = ex; + } + } + // Cancel other tasks, transition status, notify pool, and + // propagate exception to uncaught exception handler + try { + do {} while (!tryInactivate()); // ensure inactive + cancelTasks(); + runState = TERMINATED; + pool.workerTerminated(this); + } catch (Throwable ex) { // Shouldn't ever happen + if (exception == null) // but if so, at least rethrown + exception = ex; + } finally { + if (exception != null) + ForkJoinTask.rethrowException(exception); + } + } + + // Intrinsics-based support for queue operations. + + private static long slotOffset(int i) { + return ((long) i << qShift) + qBase; + } + + /** + * Adds in store-order the given task at given slot of q to null. + * Caller must ensure q is non-null and index is in range. + */ + private static void setSlot(ForkJoinTask[] q, int i, + ForkJoinTask t) { + UNSAFE.putOrderedObject(q, slotOffset(i), t); + } + + /** + * CAS given slot of q to null. Caller must ensure q is non-null + * and index is in range. + */ + private static boolean casSlotNull(ForkJoinTask[] q, int i, + ForkJoinTask t) { + return UNSAFE.compareAndSwapObject(q, slotOffset(i), t, null); + } + + /** + * Sets sp in store-order. + */ + private void storeSp(int s) { + UNSAFE.putOrderedInt(this, spOffset, s); + } + + // Main queue methods + + /** + * Pushes a task. Called only by current thread. + * + * @param t the task. Caller must ensure non-null. + */ + final void pushTask(ForkJoinTask t) { + ForkJoinTask[] q = queue; + int mask = q.length - 1; + int s = sp; + setSlot(q, s & mask, t); + storeSp(++s); + if ((s -= base) == 1) + pool.signalWork(); + else if (s >= mask) + growQueue(); + } + + /** + * Tries to take a task from the base of the queue, failing if + * either empty or contended. + * + * @return a task, or null if none or contended + */ + final ForkJoinTask deqTask() { + ForkJoinTask t; + ForkJoinTask[] q; + int i; + int b; + if (sp != (b = base) && + (q = queue) != null && // must read q after b + (t = q[i = (q.length - 1) & b]) != null && + casSlotNull(q, i, t)) { + base = b + 1; + return t; + } + return null; + } + + /** + * Tries to take a task from the base of own queue, activating if + * necessary, failing only if empty. Called only by current thread. + * + * @return a task, or null if none + */ + final ForkJoinTask locallyDeqTask() { + int b; + while (sp != (b = base)) { + if (tryActivate()) { + ForkJoinTask[] q = queue; + int i = (q.length - 1) & b; + ForkJoinTask t = q[i]; + if (t != null && casSlotNull(q, i, t)) { + base = b + 1; + return t; + } + } + } + return null; + } + + /** + * Returns a popped task, or null if empty. Ensures active status + * if non-null. Called only by current thread. + */ + final ForkJoinTask popTask() { + int s = sp; + while (s != base) { + if (tryActivate()) { + ForkJoinTask[] q = queue; + int mask = q.length - 1; + int i = (s - 1) & mask; + ForkJoinTask t = q[i]; + if (t == null || !casSlotNull(q, i, t)) + break; + storeSp(s - 1); + return t; + } + } + return null; + } + + /** + * Specialized version of popTask to pop only if + * topmost element is the given task. Called only + * by current thread while active. + * + * @param t the task. Caller must ensure non-null. + */ + final boolean unpushTask(ForkJoinTask t) { + ForkJoinTask[] q = queue; + int mask = q.length - 1; + int s = sp - 1; + if (casSlotNull(q, s & mask, t)) { + storeSp(s); + return true; + } + return false; + } + + /** + * Returns next task or null if empty or contended + */ + final ForkJoinTask peekTask() { + ForkJoinTask[] q = queue; + if (q == null) + return null; + int mask = q.length - 1; + int i = locallyFifo ? base : (sp - 1); + return q[i & mask]; + } + + /** + * Doubles queue array size. Transfers elements by emulating + * steals (deqs) from old array and placing, oldest first, into + * new array. + */ + private void growQueue() { + ForkJoinTask[] oldQ = queue; + int oldSize = oldQ.length; + int newSize = oldSize << 1; + if (newSize > MAXIMUM_QUEUE_CAPACITY) + throw new RejectedExecutionException("Queue capacity exceeded"); + ForkJoinTask[] newQ = queue = new ForkJoinTask[newSize]; + + int b = base; + int bf = b + oldSize; + int oldMask = oldSize - 1; + int newMask = newSize - 1; + do { + int oldIndex = b & oldMask; + ForkJoinTask t = oldQ[oldIndex]; + if (t != null && !casSlotNull(oldQ, oldIndex, t)) + t = null; + setSlot(newQ, b & newMask, t); + } while (++b != bf); + pool.signalWork(); + } + + /** + * Tries to steal a task from another worker. Starts at a random + * index of workers array, and probes workers until finding one + * with non-empty queue or finding that all are empty. It + * randomly selects the first n probes. If these are empty, it + * resorts to a full circular traversal, which is necessary to + * accurately set active status by caller. Also restarts if pool + * events occurred since last scan, which forces refresh of + * workers array, in case barrier was associated with resize. + * + * This method must be both fast and quiet -- usually avoiding + * memory accesses that could disrupt cache sharing etc other than + * those needed to check for and take tasks. This accounts for, + * among other things, updating random seed in place without + * storing it until exit. + * + * @return a task, or null if none found + */ + private ForkJoinTask scan() { + ForkJoinTask t = null; + int r = seed; // extract once to keep scan quiet + ForkJoinWorkerThread[] ws; // refreshed on outer loop + int mask; // must be power 2 minus 1 and > 0 + outer:do { + if ((ws = pool.workers) != null && (mask = ws.length - 1) > 0) { + int idx = r; + int probes = ~mask; // use random index while negative + for (;;) { + r = xorShift(r); // update random seed + ForkJoinWorkerThread v = ws[mask & idx]; + if (v == null || v.sp == v.base) { + if (probes <= mask) + idx = (probes++ < 0) ? r : (idx + 1); + else + break; + } + else if (!tryActivate() || (t = v.deqTask()) == null) + continue outer; // restart on contention + else + break outer; + } + } + } while (pool.hasNewSyncEvent(this)); // retry on pool events + seed = r; + return t; + } + + /** + * Gets and removes a local or stolen task. + * + * @return a task, if available + */ + final ForkJoinTask pollTask() { + ForkJoinTask t = locallyFifo ? locallyDeqTask() : popTask(); + if (t == null && (t = scan()) != null) + ++stealCount; + return t; + } + + /** + * Gets a local task. + * + * @return a task, if available + */ + final ForkJoinTask pollLocalTask() { + return locallyFifo ? locallyDeqTask() : popTask(); + } + + /** + * Returns a pool submission, if one exists, activating first. + * + * @return a submission, if available + */ + private ForkJoinTask pollSubmission() { + ForkJoinPool p = pool; + while (p.hasQueuedSubmissions()) { + ForkJoinTask t; + if (tryActivate() && (t = p.pollSubmission()) != null) + return t; + } + return null; + } + + // Methods accessed only by Pool + + /** + * Removes and cancels all tasks in queue. Can be called from any + * thread. + */ + final void cancelTasks() { + ForkJoinTask t; + while (base != sp && (t = deqTask()) != null) + t.cancelIgnoringExceptions(); + } + + /** + * Drains tasks to given collection c. + * + * @return the number of tasks drained + */ + final int drainTasksTo(Collection> c) { + int n = 0; + ForkJoinTask t; + while (base != sp && (t = deqTask()) != null) { + c.add(t); + ++n; + } + return n; + } + + /** + * Gets and clears steal count for accumulation by pool. Called + * only when known to be idle (in pool.sync and termination). + */ + final int getAndClearStealCount() { + int sc = stealCount; + stealCount = 0; + return sc; + } + + /** + * Returns {@code true} if at least one worker in the given array + * appears to have at least one queued task. + * + * @param ws array of workers + */ + static boolean hasQueuedTasks(ForkJoinWorkerThread[] ws) { + if (ws != null) { + int len = ws.length; + for (int j = 0; j < 2; ++j) { // need two passes for clean sweep + for (int i = 0; i < len; ++i) { + ForkJoinWorkerThread w = ws[i]; + if (w != null && w.sp != w.base) + return true; + } + } + } + return false; + } + + // Support methods for ForkJoinTask + + /** + * Returns an estimate of the number of tasks in the queue. + */ + final int getQueueSize() { + // suppress momentarily negative values + return Math.max(0, sp - base); + } + + /** + * Returns an estimate of the number of tasks, offset by a + * function of number of idle workers. + */ + final int getEstimatedSurplusTaskCount() { + // The halving approximates weighting idle vs non-idle workers + return (sp - base) - (pool.getIdleThreadCount() >>> 1); + } + + /** + * Scans, returning early if joinMe done. + */ + final ForkJoinTask scanWhileJoining(ForkJoinTask joinMe) { + ForkJoinTask t = pollTask(); + if (t != null && joinMe.status < 0 && sp == base) { + pushTask(t); // unsteal if done and this task would be stealable + t = null; + } + return t; + } + + /** + * Runs tasks until {@code pool.isQuiescent()}. + */ + final void helpQuiescePool() { + for (;;) { + ForkJoinTask t = pollTask(); + if (t != null) + t.quietlyExec(); + else if (tryInactivate() && pool.isQuiescent()) + break; + } + do {} while (!tryActivate()); // re-activate on exit + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long spOffset = + objectFieldOffset("sp", ForkJoinWorkerThread.class); + private static final long runStateOffset = + objectFieldOffset("runState", ForkJoinWorkerThread.class); + private static final long qBase; + private static final int qShift; + + static { + qBase = UNSAFE.arrayBaseOffset(ForkJoinTask[].class); + int s = UNSAFE.arrayIndexScale(ForkJoinTask[].class); + if ((s & (s-1)) != 0) + throw new Error("data type scale not a power of two"); + qShift = 31 - Integer.numberOfLeadingZeros(s); + } + + private static long objectFieldOffset(String field, Class klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } +} diff --git a/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java b/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java new file mode 100644 index 00000000000..e7b87f450cb --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -0,0 +1,1270 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.locks.LockSupport; +/** + * An unbounded {@link TransferQueue} based on linked nodes. + * This queue orders elements FIFO (first-in-first-out) with respect + * to any given producer. The head of the queue is that + * element that has been on the queue the longest time for some + * producer. The tail of the queue is that element that has + * been on the queue the shortest time for some producer. + * + *

Beware that, unlike in most collections, the {@code size} + * method is NOT a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current number + * of elements requires a traversal of the elements. + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + *

Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code LinkedTransferQueue} + * happen-before + * actions subsequent to the access or removal of that element from + * the {@code LinkedTransferQueue} in another thread. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.7 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public class LinkedTransferQueue extends AbstractQueue + implements TransferQueue, java.io.Serializable { + private static final long serialVersionUID = -3223113410248163686L; + + /* + * *** Overview of Dual Queues with Slack *** + * + * Dual Queues, introduced by Scherer and Scott + * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are + * (linked) queues in which nodes may represent either data or + * requests. When a thread tries to enqueue a data node, but + * encounters a request node, it instead "matches" and removes it; + * and vice versa for enqueuing requests. Blocking Dual Queues + * arrange that threads enqueuing unmatched requests block until + * other threads provide the match. Dual Synchronous Queues (see + * Scherer, Lea, & Scott + * http://www.cs.rochester.edu/u/scott/papers/2009_Scherer_CACM_SSQ.pdf) + * additionally arrange that threads enqueuing unmatched data also + * block. Dual Transfer Queues support all of these modes, as + * dictated by callers. + * + * A FIFO dual queue may be implemented using a variation of the + * Michael & Scott (M&S) lock-free queue algorithm + * (http://www.cs.rochester.edu/u/scott/papers/1996_PODC_queues.pdf). + * It maintains two pointer fields, "head", pointing to a + * (matched) node that in turn points to the first actual + * (unmatched) queue node (or null if empty); and "tail" that + * points to the last node on the queue (or again null if + * empty). For example, here is a possible queue with four data + * elements: + * + * head tail + * | | + * v v + * M -> U -> U -> U -> U + * + * The M&S queue algorithm is known to be prone to scalability and + * overhead limitations when maintaining (via CAS) these head and + * tail pointers. This has led to the development of + * contention-reducing variants such as elimination arrays (see + * Moir et al http://portal.acm.org/citation.cfm?id=1074013) and + * optimistic back pointers (see Ladan-Mozes & Shavit + * http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf). + * However, the nature of dual queues enables a simpler tactic for + * improving M&S-style implementations when dual-ness is needed. + * + * In a dual queue, each node must atomically maintain its match + * status. While there are other possible variants, we implement + * this here as: for a data-mode node, matching entails CASing an + * "item" field from a non-null data value to null upon match, and + * vice-versa for request nodes, CASing from null to a data + * value. (Note that the linearization properties of this style of + * queue are easy to verify -- elements are made available by + * linking, and unavailable by matching.) Compared to plain M&S + * queues, this property of dual queues requires one additional + * successful atomic operation per enq/deq pair. But it also + * enables lower cost variants of queue maintenance mechanics. (A + * variation of this idea applies even for non-dual queues that + * support deletion of interior elements, such as + * j.u.c.ConcurrentLinkedQueue.) + * + * Once a node is matched, its match status can never again + * change. We may thus arrange that the linked list of them + * contain a prefix of zero or more matched nodes, followed by a + * suffix of zero or more unmatched nodes. (Note that we allow + * both the prefix and suffix to be zero length, which in turn + * means that we do not use a dummy header.) If we were not + * concerned with either time or space efficiency, we could + * correctly perform enqueue and dequeue operations by traversing + * from a pointer to the initial node; CASing the item of the + * first unmatched node on match and CASing the next field of the + * trailing node on appends. (Plus some special-casing when + * initially empty). While this would be a terrible idea in + * itself, it does have the benefit of not requiring ANY atomic + * updates on head/tail fields. + * + * We introduce here an approach that lies between the extremes of + * never versus always updating queue (head and tail) pointers. + * This offers a tradeoff between sometimes requiring extra + * traversal steps to locate the first and/or last unmatched + * nodes, versus the reduced overhead and contention of fewer + * updates to queue pointers. For example, a possible snapshot of + * a queue is: + * + * head tail + * | | + * v v + * M -> M -> U -> U -> U -> U + * + * The best value for this "slack" (the targeted maximum distance + * between the value of "head" and the first unmatched node, and + * similarly for "tail") is an empirical matter. We have found + * that using very small constants in the range of 1-3 work best + * over a range of platforms. Larger values introduce increasing + * costs of cache misses and risks of long traversal chains, while + * smaller values increase CAS contention and overhead. + * + * Dual queues with slack differ from plain M&S dual queues by + * virtue of only sometimes updating head or tail pointers when + * matching, appending, or even traversing nodes; in order to + * maintain a targeted slack. The idea of "sometimes" may be + * operationalized in several ways. The simplest is to use a + * per-operation counter incremented on each traversal step, and + * to try (via CAS) to update the associated queue pointer + * whenever the count exceeds a threshold. Another, that requires + * more overhead, is to use random number generators to update + * with a given probability per traversal step. + * + * In any strategy along these lines, because CASes updating + * fields may fail, the actual slack may exceed targeted + * slack. However, they may be retried at any time to maintain + * targets. Even when using very small slack values, this + * approach works well for dual queues because it allows all + * operations up to the point of matching or appending an item + * (hence potentially allowing progress by another thread) to be + * read-only, thus not introducing any further contention. As + * described below, we implement this by performing slack + * maintenance retries only after these points. + * + * As an accompaniment to such techniques, traversal overhead can + * be further reduced without increasing contention of head + * pointer updates: Threads may sometimes shortcut the "next" link + * path from the current "head" node to be closer to the currently + * known first unmatched node, and similarly for tail. Again, this + * may be triggered with using thresholds or randomization. + * + * These ideas must be further extended to avoid unbounded amounts + * of costly-to-reclaim garbage caused by the sequential "next" + * links of nodes starting at old forgotten head nodes: As first + * described in detail by Boehm + * (http://portal.acm.org/citation.cfm?doid=503272.503282) if a GC + * delays noticing that any arbitrarily old node has become + * garbage, all newer dead nodes will also be unreclaimed. + * (Similar issues arise in non-GC environments.) To cope with + * this in our implementation, upon CASing to advance the head + * pointer, we set the "next" link of the previous head to point + * only to itself; thus limiting the length of connected dead lists. + * (We also take similar care to wipe out possibly garbage + * retaining values held in other Node fields.) However, doing so + * adds some further complexity to traversal: If any "next" + * pointer links to itself, it indicates that the current thread + * has lagged behind a head-update, and so the traversal must + * continue from the "head". Traversals trying to find the + * current tail starting from "tail" may also encounter + * self-links, in which case they also continue at "head". + * + * It is tempting in slack-based scheme to not even use CAS for + * updates (similarly to Ladan-Mozes & Shavit). However, this + * cannot be done for head updates under the above link-forgetting + * mechanics because an update may leave head at a detached node. + * And while direct writes are possible for tail updates, they + * increase the risk of long retraversals, and hence long garbage + * chains, which can be much more costly than is worthwhile + * considering that the cost difference of performing a CAS vs + * write is smaller when they are not triggered on each operation + * (especially considering that writes and CASes equally require + * additional GC bookkeeping ("write barriers") that are sometimes + * more costly than the writes themselves because of contention). + * + * Removal of interior nodes (due to timed out or interrupted + * waits, or calls to remove(x) or Iterator.remove) can use a + * scheme roughly similar to that described in Scherer, Lea, and + * Scott's SynchronousQueue. Given a predecessor, we can unsplice + * any node except the (actual) tail of the queue. To avoid + * build-up of cancelled trailing nodes, upon a request to remove + * a trailing node, it is placed in field "cleanMe" to be + * unspliced upon the next call to unsplice any other node. + * Situations needing such mechanics are not common but do occur + * in practice; for example when an unbounded series of short + * timed calls to poll repeatedly time out but never otherwise + * fall off the list because of an untimed call to take at the + * front of the queue. Note that maintaining field cleanMe does + * not otherwise much impact garbage retention even if never + * cleared by some other call because the held node will + * eventually either directly or indirectly lead to a self-link + * once off the list. + * + * *** Overview of implementation *** + * + * We use a threshold-based approach to updates, with a slack + * threshold of two -- that is, we update head/tail when the + * current pointer appears to be two or more steps away from the + * first/last node. The slack value is hard-wired: a path greater + * than one is naturally implemented by checking equality of + * traversal pointers except when the list has only one element, + * in which case we keep slack threshold at one. Avoiding tracking + * explicit counts across method calls slightly simplifies an + * already-messy implementation. Using randomization would + * probably work better if there were a low-quality dirt-cheap + * per-thread one available, but even ThreadLocalRandom is too + * heavy for these purposes. + * + * With such a small slack threshold value, it is rarely + * worthwhile to augment this with path short-circuiting; i.e., + * unsplicing nodes between head and the first unmatched node, or + * similarly for tail, rather than advancing head or tail + * proper. However, it is used (in awaitMatch) immediately before + * a waiting thread starts to block, as a final bit of helping at + * a point when contention with others is extremely unlikely + * (since if other threads that could release it are operating, + * then the current thread wouldn't be blocking). + * + * We allow both the head and tail fields to be null before any + * nodes are enqueued; initializing upon first append. This + * simplifies some other logic, as well as providing more + * efficient explicit control paths instead of letting JVMs insert + * implicit NullPointerExceptions when they are null. While not + * currently fully implemented, we also leave open the possibility + * of re-nulling these fields when empty (which is complicated to + * arrange, for little benefit.) + * + * All enqueue/dequeue operations are handled by the single method + * "xfer" with parameters indicating whether to act as some form + * of offer, put, poll, take, or transfer (each possibly with + * timeout). The relative complexity of using one monolithic + * method outweighs the code bulk and maintenance problems of + * using separate methods for each case. + * + * Operation consists of up to three phases. The first is + * implemented within method xfer, the second in tryAppend, and + * the third in method awaitMatch. + * + * 1. Try to match an existing node + * + * Starting at head, skip already-matched nodes until finding + * an unmatched node of opposite mode, if one exists, in which + * case matching it and returning, also if necessary updating + * head to one past the matched node (or the node itself if the + * list has no other unmatched nodes). If the CAS misses, then + * a loop retries advancing head by two steps until either + * success or the slack is at most two. By requiring that each + * attempt advances head by two (if applicable), we ensure that + * the slack does not grow without bound. Traversals also check + * if the initial head is now off-list, in which case they + * start at the new head. + * + * If no candidates are found and the call was untimed + * poll/offer, (argument "how" is NOW) return. + * + * 2. Try to append a new node (method tryAppend) + * + * Starting at current tail pointer, find the actual last node + * and try to append a new node (or if head was null, establish + * the first node). Nodes can be appended only if their + * predecessors are either already matched or are of the same + * mode. If we detect otherwise, then a new node with opposite + * mode must have been appended during traversal, so we must + * restart at phase 1. The traversal and update steps are + * otherwise similar to phase 1: Retrying upon CAS misses and + * checking for staleness. In particular, if a self-link is + * encountered, then we can safely jump to a node on the list + * by continuing the traversal at current head. + * + * On successful append, if the call was ASYNC, return. + * + * 3. Await match or cancellation (method awaitMatch) + * + * Wait for another thread to match node; instead cancelling if + * the current thread was interrupted or the wait timed out. On + * multiprocessors, we use front-of-queue spinning: If a node + * appears to be the first unmatched node in the queue, it + * spins a bit before blocking. In either case, before blocking + * it tries to unsplice any nodes between the current "head" + * and the first unmatched node. + * + * Front-of-queue spinning vastly improves performance of + * heavily contended queues. And so long as it is relatively + * brief and "quiet", spinning does not much impact performance + * of less-contended queues. During spins threads check their + * interrupt status and generate a thread-local random number + * to decide to occasionally perform a Thread.yield. While + * yield has underdefined specs, we assume that might it help, + * and will not hurt in limiting impact of spinning on busy + * systems. We also use smaller (1/2) spins for nodes that are + * not known to be front but whose predecessors have not + * blocked -- these "chained" spins avoid artifacts of + * front-of-queue rules which otherwise lead to alternating + * nodes spinning vs blocking. Further, front threads that + * represent phase changes (from data to request node or vice + * versa) compared to their predecessors receive additional + * chained spins, reflecting longer paths typically required to + * unblock threads during phase changes. + */ + + /** True if on multiprocessor */ + private static final boolean MP = + Runtime.getRuntime().availableProcessors() > 1; + + /** + * The number of times to spin (with randomly interspersed calls + * to Thread.yield) on multiprocessor before blocking when a node + * is apparently the first waiter in the queue. See above for + * explanation. Must be a power of two. The value is empirically + * derived -- it works pretty well across a variety of processors, + * numbers of CPUs, and OSes. + */ + private static final int FRONT_SPINS = 1 << 7; + + /** + * The number of times to spin before blocking when a node is + * preceded by another node that is apparently spinning. Also + * serves as an increment to FRONT_SPINS on phase changes, and as + * base average frequency for yielding during spins. Must be a + * power of two. + */ + private static final int CHAINED_SPINS = FRONT_SPINS >>> 1; + + /** + * Queue nodes. Uses Object, not E, for items to allow forgetting + * them after use. Relies heavily on Unsafe mechanics to minimize + * unnecessary ordering constraints: Writes that intrinsically + * precede or follow CASes use simple relaxed forms. Other + * cleanups use releasing/lazy writes. + */ + static final class Node { + final boolean isData; // false if this is a request node + volatile Object item; // initially non-null if isData; CASed to match + volatile Node next; + volatile Thread waiter; // null until waiting + + // CAS methods for fields + final boolean casNext(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); + } + + final boolean casItem(Object cmp, Object val) { + // assert cmp == null || cmp.getClass() != Node.class; + return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); + } + + /** + * Creates a new node. Uses relaxed write because item can only + * be seen if followed by CAS. + */ + Node(Object item, boolean isData) { + UNSAFE.putObject(this, itemOffset, item); // relaxed write + this.isData = isData; + } + + /** + * Links node to itself to avoid garbage retention. Called + * only after CASing head field, so uses relaxed write. + */ + final void forgetNext() { + UNSAFE.putObject(this, nextOffset, this); + } + + /** + * Sets item to self (using a releasing/lazy write) and waiter + * to null, to avoid garbage retention after extracting or + * cancelling. + */ + final void forgetContents() { + UNSAFE.putOrderedObject(this, itemOffset, this); + UNSAFE.putOrderedObject(this, waiterOffset, null); + } + + /** + * Returns true if this node has been matched, including the + * case of artificial matches due to cancellation. + */ + final boolean isMatched() { + Object x = item; + return (x == this) || ((x == null) == isData); + } + + /** + * Returns true if this is an unmatched request node. + */ + final boolean isUnmatchedRequest() { + return !isData && item == null; + } + + /** + * Returns true if a node with the given mode cannot be + * appended to this node because this node is unmatched and + * has opposite data mode. + */ + final boolean cannotPrecede(boolean haveData) { + boolean d = isData; + Object x; + return d != haveData && (x = item) != this && (x != null) == d; + } + + /** + * Tries to artificially match a data node -- used by remove. + */ + final boolean tryMatchData() { + // assert isData; + Object x = item; + if (x != null && x != this && casItem(x, null)) { + LockSupport.unpark(waiter); + return true; + } + return false; + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long nextOffset = + objectFieldOffset(UNSAFE, "next", Node.class); + private static final long itemOffset = + objectFieldOffset(UNSAFE, "item", Node.class); + private static final long waiterOffset = + objectFieldOffset(UNSAFE, "waiter", Node.class); + + private static final long serialVersionUID = -3375979862319811754L; + } + + /** head of the queue; null until first enqueue */ + transient volatile Node head; + + /** predecessor of dangling unspliceable node */ + private transient volatile Node cleanMe; // decl here reduces contention + + /** tail of the queue; null until first append */ + private transient volatile Node tail; + + // CAS methods for fields + private boolean casTail(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); + } + + private boolean casHead(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); + } + + private boolean casCleanMe(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val); + } + + /* + * Possible values for "how" argument in xfer method. + */ + private static final int NOW = 0; // for untimed poll, tryTransfer + private static final int ASYNC = 1; // for offer, put, add + private static final int SYNC = 2; // for transfer, take + private static final int TIMED = 3; // for timed poll, tryTransfer + + @SuppressWarnings("unchecked") + static E cast(Object item) { + // assert item == null || item.getClass() != Node.class; + return (E) item; + } + + /** + * Implements all queuing methods. See above for explanation. + * + * @param e the item or null for take + * @param haveData true if this is a put, else a take + * @param how NOW, ASYNC, SYNC, or TIMED + * @param nanos timeout in nanosecs, used only if mode is TIMED + * @return an item if matched, else e + * @throws NullPointerException if haveData mode but e is null + */ + private E xfer(E e, boolean haveData, int how, long nanos) { + if (haveData && (e == null)) + throw new NullPointerException(); + Node s = null; // the node to append, if needed + + retry: for (;;) { // restart on append race + + for (Node h = head, p = h; p != null;) { // find & match first node + boolean isData = p.isData; + Object item = p.item; + if (item != p && (item != null) == isData) { // unmatched + if (isData == haveData) // can't match + break; + if (p.casItem(item, e)) { // match + for (Node q = p; q != h;) { + Node n = q.next; // update head by 2 + if (n != null) // unless singleton + q = n; + if (head == h && casHead(h, q)) { + h.forgetNext(); + break; + } // advance and retry + if ((h = head) == null || + (q = h.next) == null || !q.isMatched()) + break; // unless slack < 2 + } + LockSupport.unpark(p.waiter); + return this.cast(item); + } + } + Node n = p.next; + p = (p != n) ? n : (h = head); // Use head if p offlist + } + + if (how != NOW) { // No matches available + if (s == null) + s = new Node(e, haveData); + Node pred = tryAppend(s, haveData); + if (pred == null) + continue retry; // lost race vs opposite mode + if (how != ASYNC) + return awaitMatch(s, pred, e, (how == TIMED), nanos); + } + return e; // not waiting + } + } + + /** + * Tries to append node s as tail. + * + * @param s the node to append + * @param haveData true if appending in data mode + * @return null on failure due to losing race with append in + * different mode, else s's predecessor, or s itself if no + * predecessor + */ + private Node tryAppend(Node s, boolean haveData) { + for (Node t = tail, p = t;;) { // move p to last node and append + Node n, u; // temps for reads of next & tail + if (p == null && (p = head) == null) { + if (casHead(null, s)) + return s; // initialize + } + else if (p.cannotPrecede(haveData)) + return null; // lost race vs opposite mode + else if ((n = p.next) != null) // not last; keep traversing + p = p != t && t != (u = tail) ? (t = u) : // stale tail + (p != n) ? n : null; // restart if off list + else if (!p.casNext(null, s)) + p = p.next; // re-read on CAS failure + else { + if (p != t) { // update if slack now >= 2 + while ((tail != t || !casTail(t, s)) && + (t = tail) != null && + (s = t.next) != null && // advance and retry + (s = s.next) != null && s != t); + } + return p; + } + } + } + + /** + * Spins/yields/blocks until node s is matched or caller gives up. + * + * @param s the waiting node + * @param pred the predecessor of s, or s itself if it has no + * predecessor, or null if unknown (the null case does not occur + * in any current calls but may in possible future extensions) + * @param e the comparison value for checking match + * @param timed if true, wait only until timeout elapses + * @param nanos timeout in nanosecs, used only if timed is true + * @return matched item, or e if unmatched on interrupt or timeout + */ + private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) { + long lastTime = timed ? System.nanoTime() : 0L; + Thread w = Thread.currentThread(); + int spins = -1; // initialized after first item and cancel checks + ThreadLocalRandom randomYields = null; // bound if needed + + for (;;) { + Object item = s.item; + if (item != e) { // matched + // assert item != s; + s.forgetContents(); // avoid garbage + return this.cast(item); + } + if ((w.isInterrupted() || (timed && nanos <= 0)) && + s.casItem(e, s)) { // cancel + unsplice(pred, s); + return e; + } + + if (spins < 0) { // establish spins at/near front + if ((spins = spinsFor(pred, s.isData)) > 0) + randomYields = ThreadLocalRandom.current(); + } + else if (spins > 0) { // spin + if (--spins == 0) + shortenHeadPath(); // reduce slack before blocking + else if (randomYields.nextInt(CHAINED_SPINS) == 0) + Thread.yield(); // occasionally yield + } + else if (s.waiter == null) { + s.waiter = w; // request unpark then recheck + } + else if (timed) { + long now = System.nanoTime(); + if ((nanos -= now - lastTime) > 0) + LockSupport.parkNanos(this, nanos); + lastTime = now; + } + else { + LockSupport.park(this); + s.waiter = null; + spins = -1; // spin if front upon wakeup + } + } + } + + /** + * Returns spin/yield value for a node with given predecessor and + * data mode. See above for explanation. + */ + private static int spinsFor(Node pred, boolean haveData) { + if (MP && pred != null) { + if (pred.isData != haveData) // phase change + return FRONT_SPINS + CHAINED_SPINS; + if (pred.isMatched()) // probably at front + return FRONT_SPINS; + if (pred.waiter == null) // pred apparently spinning + return CHAINED_SPINS; + } + return 0; + } + + /** + * Tries (once) to unsplice nodes between head and first unmatched + * or trailing node; failing on contention. + */ + private void shortenHeadPath() { + Node h, hn, p, q; + if ((p = h = head) != null && h.isMatched() && + (q = hn = h.next) != null) { + Node n; + while ((n = q.next) != q) { + if (n == null || !q.isMatched()) { + if (hn != q && h.next == hn) + h.casNext(hn, q); + break; + } + p = q; + q = n; + } + } + } + + /* -------------- Traversal methods -------------- */ + + /** + * Returns the successor of p, or the head node if p.next has been + * linked to self, which will only be true if traversing with a + * stale pointer that is now off the list. + */ + final Node succ(Node p) { + Node next = p.next; + return (p == next) ? head : next; + } + + /** + * Returns the first unmatched node of the given mode, or null if + * none. Used by methods isEmpty, hasWaitingConsumer. + */ + private Node firstOfMode(boolean isData) { + for (Node p = head; p != null; p = succ(p)) { + if (!p.isMatched()) + return (p.isData == isData) ? p : null; + } + return null; + } + + /** + * Returns the item in the first unmatched node with isData; or + * null if none. Used by peek. + */ + private E firstDataItem() { + for (Node p = head; p != null; p = succ(p)) { + Object item = p.item; + if (p.isData) { + if (item != null && item != p) + return this.cast(item); + } + else if (item == null) + return null; + } + return null; + } + + /** + * Traverses and counts unmatched nodes of the given mode. + * Used by methods size and getWaitingConsumerCount. + */ + private int countOfMode(boolean data) { + int count = 0; + for (Node p = head; p != null; ) { + if (!p.isMatched()) { + if (p.isData != data) + return 0; + if (++count == Integer.MAX_VALUE) // saturated + break; + } + Node n = p.next; + if (n != p) + p = n; + else { + count = 0; + p = head; + } + } + return count; + } + + final class Itr implements Iterator { + private Node nextNode; // next node to return item for + private E nextItem; // the corresponding item + private Node lastRet; // last returned node, to support remove + private Node lastPred; // predecessor to unlink lastRet + + /** + * Moves to next node after prev, or first node if prev null. + */ + private void advance(Node prev) { + lastPred = lastRet; + lastRet = prev; + for (Node p = (prev == null) ? head : succ(prev); + p != null; p = succ(p)) { + Object item = p.item; + if (p.isData) { + if (item != null && item != p) { + nextItem = LinkedTransferQueue.this.cast(item); + nextNode = p; + return; + } + } + else if (item == null) + break; + } + nextNode = null; + } + + Itr() { + advance(null); + } + + public final boolean hasNext() { + return nextNode != null; + } + + public final E next() { + Node p = nextNode; + if (p == null) throw new NoSuchElementException(); + E e = nextItem; + advance(p); + return e; + } + + public final void remove() { + Node p = lastRet; + if (p == null) throw new IllegalStateException(); + findAndRemoveDataNode(lastPred, p); + } + } + + /* -------------- Removal methods -------------- */ + + /** + * Unsplices (now or later) the given deleted/cancelled node with + * the given predecessor. + * + * @param pred predecessor of node to be unspliced + * @param s the node to be unspliced + */ + private void unsplice(Node pred, Node s) { + s.forgetContents(); // clear unneeded fields + /* + * At any given time, exactly one node on list cannot be + * unlinked -- the last inserted node. To accommodate this, if + * we cannot unlink s, we save its predecessor as "cleanMe", + * processing the previously saved version first. Because only + * one node in the list can have a null next, at least one of + * node s or the node previously saved can always be + * processed, so this always terminates. + */ + if (pred != null && pred != s) { + while (pred.next == s) { + Node oldpred = (cleanMe == null) ? null : reclean(); + Node n = s.next; + if (n != null) { + if (n != s) + pred.casNext(s, n); + break; + } + if (oldpred == pred || // Already saved + ((oldpred == null || oldpred.next == s) && + casCleanMe(oldpred, pred))) { + break; + } + } + } + } + + /** + * Tries to unsplice the deleted/cancelled node held in cleanMe + * that was previously uncleanable because it was at tail. + * + * @return current cleanMe node (or null) + */ + private Node reclean() { + /* + * cleanMe is, or at one time was, predecessor of a cancelled + * node s that was the tail so could not be unspliced. If it + * is no longer the tail, try to unsplice if necessary and + * make cleanMe slot available. This differs from similar + * code in unsplice() because we must check that pred still + * points to a matched node that can be unspliced -- if not, + * we can (must) clear cleanMe without unsplicing. This can + * loop only due to contention. + */ + Node pred; + while ((pred = cleanMe) != null) { + Node s = pred.next; + Node n; + if (s == null || s == pred || !s.isMatched()) + casCleanMe(pred, null); // already gone + else if ((n = s.next) != null) { + if (n != s) + pred.casNext(s, n); + casCleanMe(pred, null); + } + else + break; + } + return pred; + } + + /** + * Main implementation of Iterator.remove(). Finds + * and unsplices the given data node. + * + * @param possiblePred possible predecessor of s + * @param s the node to remove + */ + final void findAndRemoveDataNode(Node possiblePred, Node s) { + // assert s.isData; + if (s.tryMatchData()) { + if (possiblePred != null && possiblePred.next == s) + unsplice(possiblePred, s); // was actual predecessor + else { + for (Node pred = null, p = head; p != null; ) { + if (p == s) { + unsplice(pred, p); + break; + } + if (p.isUnmatchedRequest()) + break; + pred = p; + if ((p = p.next) == pred) { // stale + pred = null; + p = head; + } + } + } + } + } + + /** + * Main implementation of remove(Object) + */ + private boolean findAndRemove(Object e) { + if (e != null) { + for (Node pred = null, p = head; p != null; ) { + Object item = p.item; + if (p.isData) { + if (item != null && item != p && e.equals(item) && + p.tryMatchData()) { + unsplice(pred, p); + return true; + } + } + else if (item == null) + break; + pred = p; + if ((p = p.next) == pred) { // stale + pred = null; + p = head; + } + } + } + return false; + } + + + /** + * Creates an initially empty {@code LinkedTransferQueue}. + */ + public LinkedTransferQueue() { + } + + /** + * Creates a {@code LinkedTransferQueue} + * initially containing the elements of the given collection, + * added in traversal order of the collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public LinkedTransferQueue(Collection c) { + this(); + addAll(c); + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never block. + * + * @throws NullPointerException if the specified element is null + */ + public void put(E e) { + xfer(e, true, ASYNC, 0); + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never block or + * return {@code false}. + * + * @return {@code true} (as specified by + * {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e, long timeout, TimeUnit unit) { + xfer(e, true, ASYNC, 0); + return true; + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never return {@code false}. + * + * @return {@code true} (as specified by + * {@link BlockingQueue#offer(Object) BlockingQueue.offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + xfer(e, true, ASYNC, 0); + return true; + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never throw + * {@link IllegalStateException} or return {@code false}. + * + * @return {@code true} (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + xfer(e, true, ASYNC, 0); + return true; + } + + /** + * Transfers the element to a waiting consumer immediately, if possible. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * otherwise returning {@code false} without enqueuing the element. + * + * @throws NullPointerException if the specified element is null + */ + public boolean tryTransfer(E e) { + return xfer(e, true, NOW, 0) == null; + } + + /** + * Transfers the element to a consumer, waiting if necessary to do so. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else inserts the specified element at the tail of this queue + * and waits until the element is received by a consumer. + * + * @throws NullPointerException if the specified element is null + */ + public void transfer(E e) throws InterruptedException { + if (xfer(e, true, SYNC, 0) != null) { + Thread.interrupted(); // failure possible only due to interrupt + throw new InterruptedException(); + } + } + + /** + * Transfers the element to a consumer if it is possible to do so + * before the timeout elapses. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else inserts the specified element at the tail of this queue + * and waits until the element is received by a consumer, + * returning {@code false} if the specified wait time elapses + * before the element can be transferred. + * + * @throws NullPointerException if the specified element is null + */ + public boolean tryTransfer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null) + return true; + if (!Thread.interrupted()) + return false; + throw new InterruptedException(); + } + + public E take() throws InterruptedException { + E e = xfer(null, false, SYNC, 0); + if (e != null) + return e; + Thread.interrupted(); + throw new InterruptedException(); + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + E e = xfer(null, false, TIMED, unit.toNanos(timeout)); + if (e != null || !Thread.interrupted()) + return e; + throw new InterruptedException(); + } + + public E poll() { + return xfer(null, false, NOW, 0); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while ( (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while (n < maxElements && (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /** + * Returns an iterator over the elements in this queue in proper + * sequence, from head to tail. + * + *

The returned iterator is a "weakly consistent" iterator that + * will never throw + * {@link ConcurrentModificationException ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed + * to) reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this queue in proper sequence + */ + public Iterator iterator() { + return new Itr(); + } + + public E peek() { + return firstDataItem(); + } + + /** + * Returns {@code true} if this queue contains no elements. + * + * @return {@code true} if this queue contains no elements + */ + public boolean isEmpty() { + return firstOfMode(true) == null; + } + + public boolean hasWaitingConsumer() { + return firstOfMode(false) != null; + } + + /** + * Returns the number of elements in this queue. If this queue + * contains more than {@code Integer.MAX_VALUE} elements, returns + * {@code Integer.MAX_VALUE}. + * + *

Beware that, unlike in most collections, this method is + * NOT a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current + * number of elements requires an O(n) traversal. + * + * @return the number of elements in this queue + */ + public int size() { + return countOfMode(true); + } + + public int getWaitingConsumerCount() { + return countOfMode(false); + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queue contains one or more such + * elements. + * Returns {@code true} if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return {@code true} if this queue changed as a result of the call + */ + public boolean remove(Object o) { + return findAndRemove(o); + } + + /** + * Always returns {@code Integer.MAX_VALUE} because a + * {@code LinkedTransferQueue} is not capacity constrained. + * + * @return {@code Integer.MAX_VALUE} (as specified by + * {@link BlockingQueue#remainingCapacity()}) + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + /** + * Saves the state to a stream (that is, serializes it). + * + * @serialData All of the elements (each an {@code E}) in + * the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + for (E e : this) + s.writeObject(e); + // Use trailing null as sentinel + s.writeObject(null); + } + + /** + * Reconstitutes the Queue instance from a stream (that is, + * deserializes it). + * + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + for (;;) { + @SuppressWarnings("unchecked") E item = (E) s.readObject(); + if (item == null) + break; + else + offer(item); + } + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long headOffset = + objectFieldOffset(UNSAFE, "head", LinkedTransferQueue.class); + private static final long tailOffset = + objectFieldOffset(UNSAFE, "tail", LinkedTransferQueue.class); + private static final long cleanMeOffset = + objectFieldOffset(UNSAFE, "cleanMe", LinkedTransferQueue.class); + + static long objectFieldOffset(sun.misc.Unsafe UNSAFE, + String field, Class klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } + +} diff --git a/jdk/src/share/classes/java/util/concurrent/Phaser.java b/jdk/src/share/classes/java/util/concurrent/Phaser.java new file mode 100644 index 00000000000..b271539d87a --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/Phaser.java @@ -0,0 +1,1042 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.LockSupport; + +/** + * A reusable synchronization barrier, similar in functionality to + * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and + * {@link java.util.concurrent.CountDownLatch CountDownLatch} + * but supporting more flexible usage. + * + *

Registration. Unlike the case for other barriers, the + * number of parties registered to synchronize on a phaser + * may vary over time. Tasks may be registered at any time (using + * methods {@link #register}, {@link #bulkRegister}, or forms of + * constructors establishing initial numbers of parties), and + * optionally deregistered upon any arrival (using {@link + * #arriveAndDeregister}). As is the case with most basic + * synchronization constructs, registration and deregistration affect + * only internal counts; they do not establish any further internal + * bookkeeping, so tasks cannot query whether they are registered. + * (However, you can introduce such bookkeeping by subclassing this + * class.) + * + *

Synchronization. Like a {@code CyclicBarrier}, a {@code + * Phaser} may be repeatedly awaited. Method {@link + * #arriveAndAwaitAdvance} has effect analogous to {@link + * java.util.concurrent.CyclicBarrier#await CyclicBarrier.await}. Each + * generation of a {@code Phaser} has an associated phase number. The + * phase number starts at zero, and advances when all parties arrive + * at the barrier, wrapping around to zero after reaching {@code + * Integer.MAX_VALUE}. The use of phase numbers enables independent + * control of actions upon arrival at a barrier and upon awaiting + * others, via two kinds of methods that may be invoked by any + * registered party: + * + *

    + * + *
  • Arrival. Methods {@link #arrive} and + * {@link #arriveAndDeregister} record arrival at a + * barrier. These methods do not block, but return an associated + * arrival phase number; that is, the phase number of + * the barrier to which the arrival applied. When the final + * party for a given phase arrives, an optional barrier action + * is performed and the phase advances. Barrier actions, + * performed by the party triggering a phase advance, are + * arranged by overriding method {@link #onAdvance(int, int)}, + * which also controls termination. Overriding this method is + * similar to, but more flexible than, providing a barrier + * action to a {@code CyclicBarrier}. + * + *
  • Waiting. Method {@link #awaitAdvance} requires an + * argument indicating an arrival phase number, and returns when + * the barrier advances to (or is already at) a different phase. + * Unlike similar constructions using {@code CyclicBarrier}, + * method {@code awaitAdvance} continues to wait even if the + * waiting thread is interrupted. Interruptible and timeout + * versions are also available, but exceptions encountered while + * tasks wait interruptibly or with timeout do not change the + * state of the barrier. If necessary, you can perform any + * associated recovery within handlers of those exceptions, + * often after invoking {@code forceTermination}. Phasers may + * also be used by tasks executing in a {@link ForkJoinPool}, + * which will ensure sufficient parallelism to execute tasks + * when others are blocked waiting for a phase to advance. + * + *
+ * + *

Termination. A {@code Phaser} may enter a + * termination state in which all synchronization methods + * immediately return without updating phaser state or waiting for + * advance, and indicating (via a negative phase value) that execution + * is complete. Termination is triggered when an invocation of {@code + * onAdvance} returns {@code true}. As illustrated below, when + * phasers control actions with a fixed number of iterations, it is + * often convenient to override this method to cause termination when + * the current phase number reaches a threshold. Method {@link + * #forceTermination} is also available to abruptly release waiting + * threads and allow them to terminate. + * + *

Tiering. Phasers may be tiered (i.e., arranged + * in tree structures) to reduce contention. Phasers with large + * numbers of parties that would otherwise experience heavy + * synchronization contention costs may instead be set up so that + * groups of sub-phasers share a common parent. This may greatly + * increase throughput even though it incurs greater per-operation + * overhead. + * + *

Monitoring. While synchronization methods may be invoked + * only by registered parties, the current state of a phaser may be + * monitored by any caller. At any given moment there are {@link + * #getRegisteredParties} parties in total, of which {@link + * #getArrivedParties} have arrived at the current phase ({@link + * #getPhase}). When the remaining ({@link #getUnarrivedParties}) + * parties arrive, the phase advances. The values returned by these + * methods may reflect transient states and so are not in general + * useful for synchronization control. Method {@link #toString} + * returns snapshots of these state queries in a form convenient for + * informal monitoring. + * + *

Sample usages: + * + *

A {@code Phaser} may be used instead of a {@code CountDownLatch} + * to control a one-shot action serving a variable number of + * parties. The typical idiom is for the method setting this up to + * first register, then start the actions, then deregister, as in: + * + *

 {@code
+ * void runTasks(List tasks) {
+ *   final Phaser phaser = new Phaser(1); // "1" to register self
+ *   // create and start threads
+ *   for (Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         phaser.arriveAndAwaitAdvance(); // await all creation
+ *         task.run();
+ *       }
+ *     }.start();
+ *   }
+ *
+ *   // allow threads to start and deregister self
+ *   phaser.arriveAndDeregister();
+ * }}
+ * + *

One way to cause a set of threads to repeatedly perform actions + * for a given number of iterations is to override {@code onAdvance}: + * + *

 {@code
+ * void startTasks(List tasks, final int iterations) {
+ *   final Phaser phaser = new Phaser() {
+ *     protected boolean onAdvance(int phase, int registeredParties) {
+ *       return phase >= iterations || registeredParties == 0;
+ *     }
+ *   };
+ *   phaser.register();
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         do {
+ *           task.run();
+ *           phaser.arriveAndAwaitAdvance();
+ *         } while (!phaser.isTerminated());
+ *       }
+ *     }.start();
+ *   }
+ *   phaser.arriveAndDeregister(); // deregister self, don't wait
+ * }}
+ * + * If the main task must later await termination, it + * may re-register and then execute a similar loop: + *
 {@code
+ *   // ...
+ *   phaser.register();
+ *   while (!phaser.isTerminated())
+ *     phaser.arriveAndAwaitAdvance();}
+ * + *

Related constructions may be used to await particular phase numbers + * in contexts where you are sure that the phase will never wrap around + * {@code Integer.MAX_VALUE}. For example: + * + *

 {@code
+ * void awaitPhase(Phaser phaser, int phase) {
+ *   int p = phaser.register(); // assumes caller not already registered
+ *   while (p < phase) {
+ *     if (phaser.isTerminated())
+ *       // ... deal with unexpected termination
+ *     else
+ *       p = phaser.arriveAndAwaitAdvance();
+ *   }
+ *   phaser.arriveAndDeregister();
+ * }}
+ * + * + *

To create a set of tasks using a tree of phasers, + * you could use code of the following form, assuming a + * Task class with a constructor accepting a phaser that + * it registers for upon construction: + * + *

 {@code
+ * void build(Task[] actions, int lo, int hi, Phaser ph) {
+ *   if (hi - lo > TASKS_PER_PHASER) {
+ *     for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
+ *       int j = Math.min(i + TASKS_PER_PHASER, hi);
+ *       build(actions, i, j, new Phaser(ph));
+ *     }
+ *   } else {
+ *     for (int i = lo; i < hi; ++i)
+ *       actions[i] = new Task(ph);
+ *       // assumes new Task(ph) performs ph.register()
+ *   }
+ * }
+ * // .. initially called, for n tasks via
+ * build(new Task[n], 0, n, new Phaser());}
+ * + * The best value of {@code TASKS_PER_PHASER} depends mainly on + * expected barrier synchronization rates. A value as low as four may + * be appropriate for extremely small per-barrier task bodies (thus + * high rates), or up to hundreds for extremely large ones. + * + * + * + *

Implementation notes: This implementation restricts the + * maximum number of parties to 65535. Attempts to register additional + * parties result in {@code IllegalStateException}. However, you can and + * should create tiered phasers to accommodate arbitrarily large sets + * of participants. + * + * @since 1.7 + * @author Doug Lea + */ +public class Phaser { + /* + * This class implements an extension of X10 "clocks". Thanks to + * Vijay Saraswat for the idea, and to Vivek Sarkar for + * enhancements to extend functionality. + */ + + /** + * Barrier state representation. Conceptually, a barrier contains + * four values: + * + * * parties -- the number of parties to wait (16 bits) + * * unarrived -- the number of parties yet to hit barrier (16 bits) + * * phase -- the generation of the barrier (31 bits) + * * terminated -- set if barrier is terminated (1 bit) + * + * However, to efficiently maintain atomicity, these values are + * packed into a single (atomic) long. Termination uses the sign + * bit of 32 bit representation of phase, so phase is set to -1 on + * termination. Good performance relies on keeping state decoding + * and encoding simple, and keeping race windows short. + * + * Note: there are some cheats in arrive() that rely on unarrived + * count being lowest 16 bits. + */ + private volatile long state; + + private static final int ushortMask = 0xffff; + private static final int phaseMask = 0x7fffffff; + + private static int unarrivedOf(long s) { + return (int) (s & ushortMask); + } + + private static int partiesOf(long s) { + return ((int) s) >>> 16; + } + + private static int phaseOf(long s) { + return (int) (s >>> 32); + } + + private static int arrivedOf(long s) { + return partiesOf(s) - unarrivedOf(s); + } + + private static long stateFor(int phase, int parties, int unarrived) { + return ((((long) phase) << 32) | (((long) parties) << 16) | + (long) unarrived); + } + + private static long trippedStateFor(int phase, int parties) { + long lp = (long) parties; + return (((long) phase) << 32) | (lp << 16) | lp; + } + + /** + * Returns message string for bad bounds exceptions. + */ + private static String badBounds(int parties, int unarrived) { + return ("Attempt to set " + unarrived + + " unarrived of " + parties + " parties"); + } + + /** + * The parent of this phaser, or null if none + */ + private final Phaser parent; + + /** + * The root of phaser tree. Equals this if not in a tree. Used to + * support faster state push-down. + */ + private final Phaser root; + + // Wait queues + + /** + * Heads of Treiber stacks for waiting threads. To eliminate + * contention while releasing some threads while adding others, we + * use two of them, alternating across even and odd phases. + */ + private final AtomicReference evenQ = new AtomicReference(); + private final AtomicReference oddQ = new AtomicReference(); + + private AtomicReference queueFor(int phase) { + return ((phase & 1) == 0) ? evenQ : oddQ; + } + + /** + * Returns current state, first resolving lagged propagation from + * root if necessary. + */ + private long getReconciledState() { + return (parent == null) ? state : reconcileState(); + } + + /** + * Recursively resolves state. + */ + private long reconcileState() { + Phaser p = parent; + long s = state; + if (p != null) { + while (unarrivedOf(s) == 0 && phaseOf(s) != phaseOf(root.state)) { + long parentState = p.getReconciledState(); + int parentPhase = phaseOf(parentState); + int phase = phaseOf(s = state); + if (phase != parentPhase) { + long next = trippedStateFor(parentPhase, partiesOf(s)); + if (casState(s, next)) { + releaseWaiters(phase); + s = next; + } + } + } + } + return s; + } + + /** + * Creates a new phaser without any initially registered parties, + * initial phase number 0, and no parent. Any thread using this + * phaser will need to first register for it. + */ + public Phaser() { + this(null); + } + + /** + * Creates a new phaser with the given numbers of registered + * unarrived parties, initial phase number 0, and no parent. + * + * @param parties the number of parties required to trip barrier + * @throws IllegalArgumentException if parties less than zero + * or greater than the maximum number of parties supported + */ + public Phaser(int parties) { + this(null, parties); + } + + /** + * Creates a new phaser with the given parent, without any + * initially registered parties. If parent is non-null this phaser + * is registered with the parent and its initial phase number is + * the same as that of parent phaser. + * + * @param parent the parent phaser + */ + public Phaser(Phaser parent) { + int phase = 0; + this.parent = parent; + if (parent != null) { + this.root = parent.root; + phase = parent.register(); + } + else + this.root = this; + this.state = trippedStateFor(phase, 0); + } + + /** + * Creates a new phaser with the given parent and numbers of + * registered unarrived parties. If parent is non-null, this phaser + * is registered with the parent and its initial phase number is + * the same as that of parent phaser. + * + * @param parent the parent phaser + * @param parties the number of parties required to trip barrier + * @throws IllegalArgumentException if parties less than zero + * or greater than the maximum number of parties supported + */ + public Phaser(Phaser parent, int parties) { + if (parties < 0 || parties > ushortMask) + throw new IllegalArgumentException("Illegal number of parties"); + int phase = 0; + this.parent = parent; + if (parent != null) { + this.root = parent.root; + phase = parent.register(); + } + else + this.root = this; + this.state = trippedStateFor(phase, parties); + } + + /** + * Adds a new unarrived party to this phaser. + * + * @return the arrival phase number to which this registration applied + * @throws IllegalStateException if attempting to register more + * than the maximum supported number of parties + */ + public int register() { + return doRegister(1); + } + + /** + * Adds the given number of new unarrived parties to this phaser. + * + * @param parties the number of parties required to trip barrier + * @return the arrival phase number to which this registration applied + * @throws IllegalStateException if attempting to register more + * than the maximum supported number of parties + */ + public int bulkRegister(int parties) { + if (parties < 0) + throw new IllegalArgumentException(); + if (parties == 0) + return getPhase(); + return doRegister(parties); + } + + /** + * Shared code for register, bulkRegister + */ + private int doRegister(int registrations) { + int phase; + for (;;) { + long s = getReconciledState(); + phase = phaseOf(s); + int unarrived = unarrivedOf(s) + registrations; + int parties = partiesOf(s) + registrations; + if (phase < 0) + break; + if (parties > ushortMask || unarrived > ushortMask) + throw new IllegalStateException(badBounds(parties, unarrived)); + if (phase == phaseOf(root.state) && + casState(s, stateFor(phase, parties, unarrived))) + break; + } + return phase; + } + + /** + * Arrives at the barrier, but does not wait for others. (You can + * in turn wait for others via {@link #awaitAdvance}). It is an + * unenforced usage error for an unregistered party to invoke this + * method. + * + * @return the arrival phase number, or a negative value if terminated + * @throws IllegalStateException if not terminated and the number + * of unarrived parties would become negative + */ + public int arrive() { + int phase; + for (;;) { + long s = state; + phase = phaseOf(s); + if (phase < 0) + break; + int parties = partiesOf(s); + int unarrived = unarrivedOf(s) - 1; + if (unarrived > 0) { // Not the last arrival + if (casState(s, s - 1)) // s-1 adds one arrival + break; + } + else if (unarrived == 0) { // the last arrival + Phaser par = parent; + if (par == null) { // directly trip + if (casState + (s, + trippedStateFor(onAdvance(phase, parties) ? -1 : + ((phase + 1) & phaseMask), parties))) { + releaseWaiters(phase); + break; + } + } + else { // cascade to parent + if (casState(s, s - 1)) { // zeroes unarrived + par.arrive(); + reconcileState(); + break; + } + } + } + else if (phase != phaseOf(root.state)) // or if unreconciled + reconcileState(); + else + throw new IllegalStateException(badBounds(parties, unarrived)); + } + return phase; + } + + /** + * Arrives at the barrier and deregisters from it without waiting + * for others. Deregistration reduces the number of parties + * required to trip the barrier in future phases. If this phaser + * has a parent, and deregistration causes this phaser to have + * zero parties, this phaser also arrives at and is deregistered + * from its parent. It is an unenforced usage error for an + * unregistered party to invoke this method. + * + * @return the arrival phase number, or a negative value if terminated + * @throws IllegalStateException if not terminated and the number + * of registered or unarrived parties would become negative + */ + public int arriveAndDeregister() { + // similar code to arrive, but too different to merge + Phaser par = parent; + int phase; + for (;;) { + long s = state; + phase = phaseOf(s); + if (phase < 0) + break; + int parties = partiesOf(s) - 1; + int unarrived = unarrivedOf(s) - 1; + if (parties >= 0) { + if (unarrived > 0 || (unarrived == 0 && par != null)) { + if (casState + (s, + stateFor(phase, parties, unarrived))) { + if (unarrived == 0) { + par.arriveAndDeregister(); + reconcileState(); + } + break; + } + continue; + } + if (unarrived == 0) { + if (casState + (s, + trippedStateFor(onAdvance(phase, parties) ? -1 : + ((phase + 1) & phaseMask), parties))) { + releaseWaiters(phase); + break; + } + continue; + } + if (par != null && phase != phaseOf(root.state)) { + reconcileState(); + continue; + } + } + throw new IllegalStateException(badBounds(parties, unarrived)); + } + return phase; + } + + /** + * Arrives at the barrier and awaits others. Equivalent in effect + * to {@code awaitAdvance(arrive())}. If you need to await with + * interruption or timeout, you can arrange this with an analogous + * construction using one of the other forms of the awaitAdvance + * method. If instead you need to deregister upon arrival use + * {@code arriveAndDeregister}. It is an unenforced usage error + * for an unregistered party to invoke this method. + * + * @return the arrival phase number, or a negative number if terminated + * @throws IllegalStateException if not terminated and the number + * of unarrived parties would become negative + */ + public int arriveAndAwaitAdvance() { + return awaitAdvance(arrive()); + } + + /** + * Awaits the phase of the barrier to advance from the given phase + * value, returning immediately if the current phase of the + * barrier is not equal to the given phase value or this barrier + * is terminated. It is an unenforced usage error for an + * unregistered party to invoke this method. + * + * @param phase an arrival phase number, or negative value if + * terminated; this argument is normally the value returned by a + * previous call to {@code arrive} or its variants + * @return the next arrival phase number, or a negative value + * if terminated or argument is negative + */ + public int awaitAdvance(int phase) { + if (phase < 0) + return phase; + long s = getReconciledState(); + int p = phaseOf(s); + if (p != phase) + return p; + if (unarrivedOf(s) == 0 && parent != null) + parent.awaitAdvance(phase); + // Fall here even if parent waited, to reconcile and help release + return untimedWait(phase); + } + + /** + * Awaits the phase of the barrier to advance from the given phase + * value, throwing {@code InterruptedException} if interrupted + * while waiting, or returning immediately if the current phase of + * the barrier is not equal to the given phase value or this + * barrier is terminated. It is an unenforced usage error for an + * unregistered party to invoke this method. + * + * @param phase an arrival phase number, or negative value if + * terminated; this argument is normally the value returned by a + * previous call to {@code arrive} or its variants + * @return the next arrival phase number, or a negative value + * if terminated or argument is negative + * @throws InterruptedException if thread interrupted while waiting + */ + public int awaitAdvanceInterruptibly(int phase) + throws InterruptedException { + if (phase < 0) + return phase; + long s = getReconciledState(); + int p = phaseOf(s); + if (p != phase) + return p; + if (unarrivedOf(s) == 0 && parent != null) + parent.awaitAdvanceInterruptibly(phase); + return interruptibleWait(phase); + } + + /** + * Awaits the phase of the barrier to advance from the given phase + * value or the given timeout to elapse, throwing {@code + * InterruptedException} if interrupted while waiting, or + * returning immediately if the current phase of the barrier is + * not equal to the given phase value or this barrier is + * terminated. It is an unenforced usage error for an + * unregistered party to invoke this method. + * + * @param phase an arrival phase number, or negative value if + * terminated; this argument is normally the value returned by a + * previous call to {@code arrive} or its variants + * @param timeout how long to wait before giving up, in units of + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return the next arrival phase number, or a negative value + * if terminated or argument is negative + * @throws InterruptedException if thread interrupted while waiting + * @throws TimeoutException if timed out while waiting + */ + public int awaitAdvanceInterruptibly(int phase, + long timeout, TimeUnit unit) + throws InterruptedException, TimeoutException { + if (phase < 0) + return phase; + long s = getReconciledState(); + int p = phaseOf(s); + if (p != phase) + return p; + if (unarrivedOf(s) == 0 && parent != null) + parent.awaitAdvanceInterruptibly(phase, timeout, unit); + return timedWait(phase, unit.toNanos(timeout)); + } + + /** + * Forces this barrier to enter termination state. Counts of + * arrived and registered parties are unaffected. If this phaser + * has a parent, it too is terminated. This method may be useful + * for coordinating recovery after one or more tasks encounter + * unexpected exceptions. + */ + public void forceTermination() { + for (;;) { + long s = getReconciledState(); + int phase = phaseOf(s); + int parties = partiesOf(s); + int unarrived = unarrivedOf(s); + if (phase < 0 || + casState(s, stateFor(-1, parties, unarrived))) { + releaseWaiters(0); + releaseWaiters(1); + if (parent != null) + parent.forceTermination(); + return; + } + } + } + + /** + * Returns the current phase number. The maximum phase number is + * {@code Integer.MAX_VALUE}, after which it restarts at + * zero. Upon termination, the phase number is negative. + * + * @return the phase number, or a negative value if terminated + */ + public final int getPhase() { + return phaseOf(getReconciledState()); + } + + /** + * Returns the number of parties registered at this barrier. + * + * @return the number of parties + */ + public int getRegisteredParties() { + return partiesOf(state); + } + + /** + * Returns the number of registered parties that have arrived at + * the current phase of this barrier. + * + * @return the number of arrived parties + */ + public int getArrivedParties() { + return arrivedOf(state); + } + + /** + * Returns the number of registered parties that have not yet + * arrived at the current phase of this barrier. + * + * @return the number of unarrived parties + */ + public int getUnarrivedParties() { + return unarrivedOf(state); + } + + /** + * Returns the parent of this phaser, or {@code null} if none. + * + * @return the parent of this phaser, or {@code null} if none + */ + public Phaser getParent() { + return parent; + } + + /** + * Returns the root ancestor of this phaser, which is the same as + * this phaser if it has no parent. + * + * @return the root ancestor of this phaser + */ + public Phaser getRoot() { + return root; + } + + /** + * Returns {@code true} if this barrier has been terminated. + * + * @return {@code true} if this barrier has been terminated + */ + public boolean isTerminated() { + return getPhase() < 0; + } + + /** + * Overridable method to perform an action upon impending phase + * advance, and to control termination. This method is invoked + * upon arrival of the party tripping the barrier (when all other + * waiting parties are dormant). If this method returns {@code + * true}, then, rather than advance the phase number, this barrier + * will be set to a final termination state, and subsequent calls + * to {@link #isTerminated} will return true. Any (unchecked) + * Exception or Error thrown by an invocation of this method is + * propagated to the party attempting to trip the barrier, in + * which case no advance occurs. + * + *

The arguments to this method provide the state of the phaser + * prevailing for the current transition. (When called from within + * an implementation of {@code onAdvance} the values returned by + * methods such as {@code getPhase} may or may not reliably + * indicate the state to which this transition applies.) + * + *

The default version returns {@code true} when the number of + * registered parties is zero. Normally, overrides that arrange + * termination for other reasons should also preserve this + * property. + * + *

You may override this method to perform an action with side + * effects visible to participating tasks, but it is only sensible + * to do so in designs where all parties register before any + * arrive, and all {@link #awaitAdvance} at each phase. + * Otherwise, you cannot ensure lack of interference from other + * parties during the invocation of this method. Additionally, + * method {@code onAdvance} may be invoked more than once per + * transition if registrations are intermixed with arrivals. + * + * @param phase the phase number on entering the barrier + * @param registeredParties the current number of registered parties + * @return {@code true} if this barrier should terminate + */ + protected boolean onAdvance(int phase, int registeredParties) { + return registeredParties <= 0; + } + + /** + * Returns a string identifying this phaser, as well as its + * state. The state, in brackets, includes the String {@code + * "phase = "} followed by the phase number, {@code "parties = "} + * followed by the number of registered parties, and {@code + * "arrived = "} followed by the number of arrived parties. + * + * @return a string identifying this barrier, as well as its state + */ + public String toString() { + long s = getReconciledState(); + return super.toString() + + "[phase = " + phaseOf(s) + + " parties = " + partiesOf(s) + + " arrived = " + arrivedOf(s) + "]"; + } + + // methods for waiting + + /** + * Wait nodes for Treiber stack representing wait queue + */ + static final class QNode implements ForkJoinPool.ManagedBlocker { + final Phaser phaser; + final int phase; + final long startTime; + final long nanos; + final boolean timed; + final boolean interruptible; + volatile boolean wasInterrupted = false; + volatile Thread thread; // nulled to cancel wait + QNode next; + QNode(Phaser phaser, int phase, boolean interruptible, + boolean timed, long startTime, long nanos) { + this.phaser = phaser; + this.phase = phase; + this.timed = timed; + this.interruptible = interruptible; + this.startTime = startTime; + this.nanos = nanos; + thread = Thread.currentThread(); + } + public boolean isReleasable() { + return (thread == null || + phaser.getPhase() != phase || + (interruptible && wasInterrupted) || + (timed && (nanos - (System.nanoTime() - startTime)) <= 0)); + } + public boolean block() { + if (Thread.interrupted()) { + wasInterrupted = true; + if (interruptible) + return true; + } + if (!timed) + LockSupport.park(this); + else { + long waitTime = nanos - (System.nanoTime() - startTime); + if (waitTime <= 0) + return true; + LockSupport.parkNanos(this, waitTime); + } + return isReleasable(); + } + void signal() { + Thread t = thread; + if (t != null) { + thread = null; + LockSupport.unpark(t); + } + } + boolean doWait() { + if (thread != null) { + try { + ForkJoinPool.managedBlock(this, false); + } catch (InterruptedException ie) { + } + } + return wasInterrupted; + } + + } + + /** + * Removes and signals waiting threads from wait queue. + */ + private void releaseWaiters(int phase) { + AtomicReference head = queueFor(phase); + QNode q; + while ((q = head.get()) != null) { + if (head.compareAndSet(q, q.next)) + q.signal(); + } + } + + /** + * Tries to enqueue given node in the appropriate wait queue. + * + * @return true if successful + */ + private boolean tryEnqueue(QNode node) { + AtomicReference head = queueFor(node.phase); + return head.compareAndSet(node.next = head.get(), node); + } + + /** + * Enqueues node and waits unless aborted or signalled. + * + * @return current phase + */ + private int untimedWait(int phase) { + QNode node = null; + boolean queued = false; + boolean interrupted = false; + int p; + while ((p = getPhase()) == phase) { + if (Thread.interrupted()) + interrupted = true; + else if (node == null) + node = new QNode(this, phase, false, false, 0, 0); + else if (!queued) + queued = tryEnqueue(node); + else + interrupted = node.doWait(); + } + if (node != null) + node.thread = null; + releaseWaiters(phase); + if (interrupted) + Thread.currentThread().interrupt(); + return p; + } + + /** + * Interruptible version + * @return current phase + */ + private int interruptibleWait(int phase) throws InterruptedException { + QNode node = null; + boolean queued = false; + boolean interrupted = false; + int p; + while ((p = getPhase()) == phase && !interrupted) { + if (Thread.interrupted()) + interrupted = true; + else if (node == null) + node = new QNode(this, phase, true, false, 0, 0); + else if (!queued) + queued = tryEnqueue(node); + else + interrupted = node.doWait(); + } + if (node != null) + node.thread = null; + if (p != phase || (p = getPhase()) != phase) + releaseWaiters(phase); + if (interrupted) + throw new InterruptedException(); + return p; + } + + /** + * Timeout version. + * @return current phase + */ + private int timedWait(int phase, long nanos) + throws InterruptedException, TimeoutException { + long startTime = System.nanoTime(); + QNode node = null; + boolean queued = false; + boolean interrupted = false; + int p; + while ((p = getPhase()) == phase && !interrupted) { + if (Thread.interrupted()) + interrupted = true; + else if (nanos - (System.nanoTime() - startTime) <= 0) + break; + else if (node == null) + node = new QNode(this, phase, true, true, startTime, nanos); + else if (!queued) + queued = tryEnqueue(node); + else + interrupted = node.doWait(); + } + if (node != null) + node.thread = null; + if (p != phase || (p = getPhase()) != phase) + releaseWaiters(phase); + if (interrupted) + throw new InterruptedException(); + if (p == phase) + throw new TimeoutException(); + return p; + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long stateOffset = + objectFieldOffset("state", Phaser.class); + + private final boolean casState(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, stateOffset, cmp, val); + } + + private static long objectFieldOffset(String field, Class klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } +} diff --git a/jdk/src/share/classes/java/util/concurrent/RecursiveAction.java b/jdk/src/share/classes/java/util/concurrent/RecursiveAction.java new file mode 100644 index 00000000000..f622da288ac --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/RecursiveAction.java @@ -0,0 +1,179 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A recursive resultless {@link ForkJoinTask}. This class + * establishes conventions to parameterize resultless actions as + * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the + * only valid value of type {@code Void}, methods such as join always + * return {@code null} upon completion. + * + *

Sample Usages. Here is a sketch of a ForkJoin sort that + * sorts a given {@code long[]} array: + * + *

 {@code
+ * class SortTask extends RecursiveAction {
+ *   final long[] array; final int lo; final int hi;
+ *   SortTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD)
+ *       sequentiallySort(array, lo, hi);
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new SortTask(array, lo, mid),
+ *                 new SortTask(array, mid, hi));
+ *       merge(array, lo, hi);
+ *     }
+ *   }
+ * }}
+ * + * You could then sort {@code anArray} by creating {@code new + * SortTask(anArray, 0, anArray.length-1) } and invoking it in a + * ForkJoinPool. As a more concrete simple example, the following + * task increments each element of an array: + *
 {@code
+ * class IncrementTask extends RecursiveAction {
+ *   final long[] array; final int lo; final int hi;
+ *   IncrementTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD) {
+ *       for (int i = lo; i < hi; ++i)
+ *         array[i]++;
+ *     }
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new IncrementTask(array, lo, mid),
+ *                 new IncrementTask(array, mid, hi));
+ *     }
+ *   }
+ * }}
+ * + *

The following example illustrates some refinements and idioms + * that may lead to better performance: RecursiveActions need not be + * fully recursive, so long as they maintain the basic + * divide-and-conquer approach. Here is a class that sums the squares + * of each element of a double array, by subdividing out only the + * right-hand-sides of repeated divisions by two, and keeping track of + * them with a chain of {@code next} references. It uses a dynamic + * threshold based on method {@code getSurplusQueuedTaskCount}, but + * counterbalances potential excess partitioning by directly + * performing leaf actions on unstolen tasks rather than further + * subdividing. + * + *

 {@code
+ * double sumOfSquares(ForkJoinPool pool, double[] array) {
+ *   int n = array.length;
+ *   Applyer a = new Applyer(array, 0, n, null);
+ *   pool.invoke(a);
+ *   return a.result;
+ * }
+ *
+ * class Applyer extends RecursiveAction {
+ *   final double[] array;
+ *   final int lo, hi;
+ *   double result;
+ *   Applyer next; // keeps track of right-hand-side tasks
+ *   Applyer(double[] array, int lo, int hi, Applyer next) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *
+ *   double atLeaf(int l, int h) {
+ *     double sum = 0;
+ *     for (int i = l; i < h; ++i) // perform leftmost base step
+ *       sum += array[i] * array[i];
+ *     return sum;
+ *   }
+ *
+ *   protected void compute() {
+ *     int l = lo;
+ *     int h = hi;
+ *     Applyer right = null;
+ *     while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) {
+ *        int mid = (l + h) >>> 1;
+ *        right = new Applyer(array, mid, h, right);
+ *        right.fork();
+ *        h = mid;
+ *     }
+ *     double sum = atLeaf(l, h);
+ *     while (right != null) {
+ *        if (right.tryUnfork()) // directly calculate if not stolen
+ *          sum += right.atLeaf(right.lo, right.hi);
+ *       else {
+ *          right.helpJoin();
+ *          sum += right.result;
+ *        }
+ *        right = right.next;
+ *      }
+ *     result = sum;
+ *   }
+ * }}
+ * + * @since 1.7 + * @author Doug Lea + */ +public abstract class RecursiveAction extends ForkJoinTask { + private static final long serialVersionUID = 5232453952276485070L; + + /** + * The main computation performed by this task. + */ + protected abstract void compute(); + + /** + * Always returns null. + */ + public final Void getRawResult() { return null; } + + /** + * Requires null completion value. + */ + protected final void setRawResult(Void mustBeNull) { } + + /** + * Implements execution conventions for RecursiveActions. + */ + protected final boolean exec() { + compute(); + return true; + } + +} diff --git a/jdk/src/share/classes/java/util/concurrent/RecursiveTask.java b/jdk/src/share/classes/java/util/concurrent/RecursiveTask.java new file mode 100644 index 00000000000..5c624efb10f --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/RecursiveTask.java @@ -0,0 +1,97 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A recursive result-bearing {@link ForkJoinTask}. + * + *

For a classic example, here is a task computing Fibonacci numbers: + * + *

 {@code
+ * class Fibonacci extends RecursiveTask {
+ *   final int n;
+ *   Fibonacci(int n) { this.n = n; }
+ *   Integer compute() {
+ *     if (n <= 1)
+ *        return n;
+ *     Fibonacci f1 = new Fibonacci(n - 1);
+ *     f1.fork();
+ *     Fibonacci f2 = new Fibonacci(n - 2);
+ *     return f2.compute() + f1.join();
+ *   }
+ * }}
+ * + * However, besides being a dumb way to compute Fibonacci functions + * (there is a simple fast linear algorithm that you'd use in + * practice), this is likely to perform poorly because the smallest + * subtasks are too small to be worthwhile splitting up. Instead, as + * is the case for nearly all fork/join applications, you'd pick some + * minimum granularity size (for example 10 here) for which you always + * sequentially solve rather than subdividing. + * + * @since 1.7 + * @author Doug Lea + */ +public abstract class RecursiveTask extends ForkJoinTask { + private static final long serialVersionUID = 5232453952276485270L; + + /** + * The result of the computation. + */ + V result; + + /** + * The main computation performed by this task. + */ + protected abstract V compute(); + + public final V getRawResult() { + return result; + } + + protected final void setRawResult(V value) { + result = value; + } + + /** + * Implements execution conventions for RecursiveTask. + */ + protected final boolean exec() { + result = compute(); + return true; + } + +} diff --git a/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java b/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java index 67a8b32205e..06ed3c802ee 100644 --- a/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -61,6 +61,14 @@ import java.util.*; * causes tasks to be immediately removed from the work queue at * time of cancellation. * + *

Successive executions of a task scheduled via + * scheduleAtFixedRate or + * scheduleWithFixedDelay do not overlap. While different + * executions may be performed by different threads, the effects of + * prior executions happen-before + * those of subsequent ones. + * *

While this class inherits from {@link ThreadPoolExecutor}, a few * of the inherited tuning methods are not useful for it. In * particular, because it acts as a fixed-sized pool using diff --git a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java new file mode 100644 index 00000000000..3abd8dd253a --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -0,0 +1,228 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.Random; + +/** + * A random number generator isolated to the current thread. Like the + * global {@link java.util.Random} generator used by the {@link + * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized + * with an internally generated seed that may not otherwise be + * modified. When applicable, use of {@code ThreadLocalRandom} rather + * than shared {@code Random} objects in concurrent programs will + * typically encounter much less overhead and contention. Use of + * {@code ThreadLocalRandom} is particularly appropriate when multiple + * tasks (for example, each a {@link ForkJoinTask}) use random numbers + * in parallel in thread pools. + * + *

Usages of this class should typically be of the form: + * {@code ThreadLocalRandom.current().nextX(...)} (where + * {@code X} is {@code Int}, {@code Long}, etc). + * When all usages are of this form, it is never possible to + * accidently share a {@code ThreadLocalRandom} across multiple threads. + * + *

This class also provides additional commonly used bounded random + * generation methods. + * + * @since 1.7 + * @author Doug Lea + */ +public class ThreadLocalRandom extends Random { + // same constants as Random, but must be redeclared because private + private final static long multiplier = 0x5DEECE66DL; + private final static long addend = 0xBL; + private final static long mask = (1L << 48) - 1; + + /** + * The random seed. We can't use super.seed. + */ + private long rnd; + + /** + * Initialization flag to permit the first and only allowed call + * to setSeed (inside Random constructor) to succeed. We can't + * allow others since it would cause setting seed in one part of a + * program to unintentionally impact other usages by the thread. + */ + boolean initialized; + + // Padding to help avoid memory contention among seed updates in + // different TLRs in the common case that they are located near + // each other. + private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; + + /** + * The actual ThreadLocal + */ + private static final ThreadLocal localRandom = + new ThreadLocal() { + protected ThreadLocalRandom initialValue() { + return new ThreadLocalRandom(); + } + }; + + + /** + * Constructor called only by localRandom.initialValue. + * We rely on the fact that the superclass no-arg constructor + * invokes setSeed exactly once to initialize. + */ + ThreadLocalRandom() { + super(); + } + + /** + * Returns the current thread's {@code ThreadLocalRandom}. + * + * @return the current thread's {@code ThreadLocalRandom} + */ + public static ThreadLocalRandom current() { + return localRandom.get(); + } + + /** + * Throws {@code UnsupportedOperationException}. Setting seeds in + * this generator is not supported. + * + * @throws UnsupportedOperationException always + */ + public void setSeed(long seed) { + if (initialized) + throw new UnsupportedOperationException(); + initialized = true; + rnd = (seed ^ multiplier) & mask; + } + + protected int next(int bits) { + rnd = (rnd * multiplier + addend) & mask; + return (int) (rnd >>> (48-bits)); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @throws IllegalArgumentException if least greater than or equal + * to bound + * @return the next value + */ + public int nextInt(int least, int bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextInt(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public long nextLong(long n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + // Divide n by two until small enough for nextInt. On each + // iteration (at most 31 of them but usually much less), + // randomly choose both whether to include high bit in result + // (offset) and whether to continue with the lower vs upper + // half (which makes a difference only if odd). + long offset = 0; + while (n >= Integer.MAX_VALUE) { + int bits = next(2); + long half = n >>> 1; + long nextn = ((bits & 2) == 0) ? half : n - half; + if ((bits & 1) == 0) + offset += n - nextn; + n = nextn; + } + return offset + nextInt((int) n); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public long nextLong(long least, long bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextLong(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed {@code double} value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public double nextDouble(double n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + return nextDouble() * n; + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public double nextDouble(double least, double bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextDouble() * (bound - least) + least; + } + + private static final long serialVersionUID = -5851777807851030925L; +} diff --git a/jdk/src/share/classes/java/util/concurrent/TransferQueue.java b/jdk/src/share/classes/java/util/concurrent/TransferQueue.java new file mode 100644 index 00000000000..89688c3a8da --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/TransferQueue.java @@ -0,0 +1,161 @@ +/* + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A {@link BlockingQueue} in which producers may wait for consumers + * to receive elements. A {@code TransferQueue} may be useful for + * example in message passing applications in which producers + * sometimes (using method {@link #transfer}) await receipt of + * elements by consumers invoking {@code take} or {@code poll}, while + * at other times enqueue elements (via method {@code put}) without + * waiting for receipt. + * {@linkplain #tryTransfer(Object) Non-blocking} and + * {@linkplain #tryTransfer(Object,long,TimeUnit) time-out} versions of + * {@code tryTransfer} are also available. + * A {@code TransferQueue} may also be queried, via {@link + * #hasWaitingConsumer}, whether there are any threads waiting for + * items, which is a converse analogy to a {@code peek} operation. + * + *

Like other blocking queues, a {@code TransferQueue} may be + * capacity bounded. If so, an attempted transfer operation may + * initially block waiting for available space, and/or subsequently + * block waiting for reception by a consumer. Note that in a queue + * with zero capacity, such as {@link SynchronousQueue}, {@code put} + * and {@code transfer} are effectively synonymous. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @since 1.7 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public interface TransferQueue extends BlockingQueue { + /** + * Transfers the element to a waiting consumer immediately, if possible. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * otherwise returning {@code false} without enqueuing the element. + * + * @param e the element to transfer + * @return {@code true} if the element was transferred, else + * {@code false} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean tryTransfer(E e); + + /** + * Transfers the element to a consumer, waiting if necessary to do so. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else waits until the element is received by a consumer. + * + * @param e the element to transfer + * @throws InterruptedException if interrupted while waiting, + * in which case the element is not left enqueued + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + void transfer(E e) throws InterruptedException; + + /** + * Transfers the element to a consumer if it is possible to do so + * before the timeout elapses. + * + *

More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else waits until the element is received by a consumer, + * returning {@code false} if the specified wait time elapses + * before the element can be transferred. + * + * @param e the element to transfer + * @param timeout how long to wait before giving up, in units of + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return {@code true} if successful, or {@code false} if + * the specified waiting time elapses before completion, + * in which case the element is not left enqueued + * @throws InterruptedException if interrupted while waiting, + * in which case the element is not left enqueued + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean tryTransfer(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Returns {@code true} if there is at least one consumer waiting + * to receive an element via {@link #take} or + * timed {@link #poll(long,TimeUnit) poll}. + * The return value represents a momentary state of affairs. + * + * @return {@code true} if there is at least one waiting consumer + */ + boolean hasWaitingConsumer(); + + /** + * Returns an estimate of the number of consumers waiting to + * receive elements via {@link #take} or timed + * {@link #poll(long,TimeUnit) poll}. The return value is an + * approximation of a momentary state of affairs, that may be + * inaccurate if consumers have completed or given up waiting. + * The value may be useful for monitoring and heuristics, but + * not for synchronization control. Implementations of this + * method are likely to be noticeably slower than those for + * {@link #hasWaitingConsumer}. + * + * @return the number of consumers waiting to receive elements + */ + int getWaitingConsumerCount(); +} diff --git a/jdk/src/share/classes/java/util/concurrent/locks/Condition.java b/jdk/src/share/classes/java/util/concurrent/locks/Condition.java index b633b62f35d..f6714bac805 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/Condition.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/Condition.java @@ -170,8 +170,8 @@ import java.util.Date; *

As interruption generally implies cancellation, and checks for * interruption are often infrequent, an implementation can favor responding * to an interrupt over normal method return. This is true even if it can be - * shown that the interrupt occurred after another action may have unblocked - * the thread. An implementation should document this behavior. + * shown that the interrupt occurred after another action that may have + * unblocked the thread. An implementation should document this behavior. * * @since 1.5 * @author Doug Lea diff --git a/jdk/src/share/classes/java/util/concurrent/package-info.java b/jdk/src/share/classes/java/util/concurrent/package-info.java index d2f69bae841..2bcac625efe 100644 --- a/jdk/src/share/classes/java/util/concurrent/package-info.java +++ b/jdk/src/share/classes/java/util/concurrent/package-info.java @@ -92,6 +92,13 @@ * assists in coordinating the processing of groups of * asynchronous tasks. * + *

Class {@link java.util.concurrent.ForkJoinPool} provides an + * Executor primarily designed for processing instances of {@link + * java.util.concurrent.ForkJoinTask} and its subclasses. These + * classes employ a work-stealing scheduler that attains high + * throughput for tasks conforming to restrictions that often hold in + * computation-intensive parallel processing. + * *

Queues

* * The {@link java.util.concurrent.ConcurrentLinkedQueue} class @@ -110,6 +117,12 @@ * for producer-consumer, messaging, parallel tasking, and * related concurrent designs. * + *

Extended interface {@link java.util.concurrent.TransferQueue}, + * and implementation {@link java.util.concurrent.LinkedTransferQueue} + * introduce a synchronous {@code transfer} method (along with related + * features) in which a producer may optionally block awaiting its + * consumer. + * *

The {@link java.util.concurrent.BlockingDeque} interface * extends {@code BlockingQueue} to support both FIFO and LIFO * (stack-based) operations. @@ -136,15 +149,28 @@ * *

Synchronizers

* - * Four classes aid common special-purpose synchronization idioms. - * {@link java.util.concurrent.Semaphore} is a classic concurrency tool. - * {@link java.util.concurrent.CountDownLatch} is a very simple yet very - * common utility for blocking until a given number of signals, events, - * or conditions hold. A {@link java.util.concurrent.CyclicBarrier} is a - * resettable multiway synchronization point useful in some styles of - * parallel programming. An {@link java.util.concurrent.Exchanger} allows - * two threads to exchange objects at a rendezvous point, and is useful - * in several pipeline designs. + * Five classes aid common special-purpose synchronization idioms. + *
    + * + *
  • {@link java.util.concurrent.Semaphore} is a classic concurrency tool. + * + *
  • {@link java.util.concurrent.CountDownLatch} is a very simple yet + * very common utility for blocking until a given number of signals, + * events, or conditions hold. + * + *
  • A {@link java.util.concurrent.CyclicBarrier} is a resettable + * multiway synchronization point useful in some styles of parallel + * programming. + * + *
  • A {@link java.util.concurrent.Phaser} provides + * a more flexible form of barrier that may be used to control phased + * computation among multiple threads. + * + *
  • An {@link java.util.concurrent.Exchanger} allows two threads to + * exchange objects at a rendezvous point, and is useful in several + * pipeline designs. + * + *
* *

Concurrent Collections

* @@ -259,7 +285,8 @@ * in each thread happen-before those subsequent to the * corresponding {@code exchange()} in another thread. * - *
  • Actions prior to calling {@code CyclicBarrier.await} + *
  • Actions prior to calling {@code CyclicBarrier.await} and + * {@code Phaser.awaitAdvance} (as well as its variants) * happen-before actions performed by the barrier action, and * actions performed by the barrier action happen-before actions * subsequent to a successful return from the corresponding {@code await} diff --git a/jdk/src/share/classes/javax/swing/ToolTipManager.java b/jdk/src/share/classes/javax/swing/ToolTipManager.java index 6ee279bff36..63258349a47 100644 --- a/jdk/src/share/classes/javax/swing/ToolTipManager.java +++ b/jdk/src/share/classes/javax/swing/ToolTipManager.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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,10 +27,7 @@ package javax.swing; import java.awt.event.*; -import java.applet.*; import java.awt.*; -import java.io.Serializable; -import sun.swing.UIAction; /** * Manages all the ToolTips in the system. @@ -60,7 +57,7 @@ public class ToolTipManager extends MouseAdapter implements MouseMotionListener JComponent insideComponent; MouseEvent mouseEvent; boolean showImmediately; - final static ToolTipManager sharedInstance = new ToolTipManager(); + private static final Object TOOL_TIP_MANAGER_KEY = new Object(); transient Popup tipWindow; /** The Window tip is being displayed in. This will be non-null if * the Window tip is in differs from that of insideComponent's Window. @@ -345,7 +342,13 @@ public class ToolTipManager extends MouseAdapter implements MouseMotionListener * @return a shared ToolTipManager object */ public static ToolTipManager sharedInstance() { - return sharedInstance; + Object value = SwingUtilities.appContextGet(TOOL_TIP_MANAGER_KEY); + if (value instanceof ToolTipManager) { + return (ToolTipManager) value; + } + ToolTipManager manager = new ToolTipManager(); + SwingUtilities.appContextPut(TOOL_TIP_MANAGER_KEY, manager); + return manager; } // add keylistener here to trigger tip for access diff --git a/jdk/src/share/classes/javax/swing/UIManager.java b/jdk/src/share/classes/javax/swing/UIManager.java index e4c7c7c687d..4dee6f3198a 100644 --- a/jdk/src/share/classes/javax/swing/UIManager.java +++ b/jdk/src/share/classes/javax/swing/UIManager.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -197,6 +197,8 @@ public class UIManager implements Serializable Vector auxLookAndFeels = null; SwingPropertyChangeSupport changeSupport; + LookAndFeelInfo[] installedLAFs; + UIDefaults getLookAndFeelDefaults() { return tables[0]; } void setLookAndFeelDefaults(UIDefaults x) { tables[0] = x; } @@ -227,18 +229,6 @@ public class UIManager implements Serializable */ private static final Object classLock = new Object(); - - /* Cache the last referenced LAFState to improve performance - * when accessing it. The cache is based on last thread rather - * than last AppContext because of the cost of looking up the - * AppContext each time. Since most Swing UI work is on the - * EventDispatchThread, this hits often enough to justify the - * overhead. (4193032) - */ - private static Thread currentLAFStateThread = null; - private static LAFState currentLAFState = null; - - /** * Return the LAFState object, lazily create one if necessary. * All access to the LAFState fields is done via this method, @@ -248,13 +238,6 @@ public class UIManager implements Serializable * */ private static LAFState getLAFState() { - // First check whether we're running on the same thread as - // the last request. - Thread thisThread = Thread.currentThread(); - if (thisThread == currentLAFStateThread) { - return currentLAFState; - } - LAFState rv = (LAFState)SwingUtilities.appContextGet( SwingUtilities2.LAF_STATE_KEY); if (rv == null) { @@ -268,10 +251,6 @@ public class UIManager implements Serializable } } } - - currentLAFStateThread = thisThread; - currentLAFState = rv; - return rv; } @@ -431,7 +410,10 @@ public class UIManager implements Serializable */ public static LookAndFeelInfo[] getInstalledLookAndFeels() { maybeInitialize(); - LookAndFeelInfo[] ilafs = installedLAFs; + LookAndFeelInfo[] ilafs = getLAFState().installedLAFs; + if (ilafs == null) { + ilafs = installedLAFs; + } LookAndFeelInfo[] rv = new LookAndFeelInfo[ilafs.length]; System.arraycopy(ilafs, 0, rv, 0, ilafs.length); return rv; @@ -453,9 +435,10 @@ public class UIManager implements Serializable public static void setInstalledLookAndFeels(LookAndFeelInfo[] infos) throws SecurityException { + maybeInitialize(); LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length]; System.arraycopy(infos, 0, newInfos, 0, infos.length); - installedLAFs = newInfos; + getLAFState().installedLAFs = newInfos; } @@ -1307,10 +1290,11 @@ public class UIManager implements Serializable } } - installedLAFs = new LookAndFeelInfo[ilafs.size()]; + LookAndFeelInfo[] installedLAFs = new LookAndFeelInfo[ilafs.size()]; for(int i = 0; i < ilafs.size(); i++) { installedLAFs[i] = ilafs.elementAt(i); } + getLAFState().installedLAFs = installedLAFs; } diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java index 5dc98f2c17e..7daf35c7071 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java @@ -26,6 +26,8 @@ package javax.swing.plaf.basic; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import java.awt.*; import java.awt.event.*; import java.io.Serializable; @@ -44,9 +46,6 @@ import javax.swing.text.View; * @author Jeff Dinkins */ public class BasicButtonUI extends ButtonUI{ - // Shared UI object - private final static BasicButtonUI buttonUI = new BasicButtonUI(); - // Visual constants // NOTE: This is not used or set any where. Were we allowed to remove // fields, this would be removed. @@ -61,10 +60,19 @@ public class BasicButtonUI extends ButtonUI{ private final static String propertyPrefix = "Button" + "."; + private static final Object BASIC_BUTTON_UI_KEY = new Object(); + // ******************************** // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + BasicButtonUI buttonUI = + (BasicButtonUI) appContext.get(BASIC_BUTTON_UI_KEY); + if (buttonUI == null) { + buttonUI = new BasicButtonUI(); + appContext.put(BASIC_BUTTON_UI_KEY, buttonUI); + } return buttonUI; } diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java index 443d05999ce..3d048d8b588 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java @@ -25,6 +25,8 @@ package javax.swing.plaf.basic; +import sun.awt.AppContext; + import javax.swing.*; import java.awt.*; @@ -49,7 +51,7 @@ import java.io.Serializable; */ public class BasicCheckBoxUI extends BasicRadioButtonUI { - private final static BasicCheckBoxUI checkboxUI = new BasicCheckBoxUI(); + private static final Object BASIC_CHECK_BOX_UI_KEY = new Object(); private final static String propertyPrefix = "CheckBox" + "."; @@ -57,6 +59,13 @@ public class BasicCheckBoxUI extends BasicRadioButtonUI { // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + BasicCheckBoxUI checkboxUI = + (BasicCheckBoxUI) appContext.get(BASIC_CHECK_BOX_UI_KEY); + if (checkboxUI == null) { + checkboxUI = new BasicCheckBoxUI(); + appContext.put(BASIC_CHECK_BOX_UI_KEY, checkboxUI); + } return checkboxUI; } diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java index 9ca6dcd4e2c..2e663fb8449 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java @@ -28,6 +28,8 @@ package javax.swing.plaf.basic; import sun.swing.SwingUtilities2; import sun.swing.DefaultLookup; import sun.swing.UIAction; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.plaf.*; import javax.swing.text.View; @@ -63,7 +65,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener * name in defaults table under the key "LabelUI". */ protected static BasicLabelUI labelUI = new BasicLabelUI(); - private final static BasicLabelUI SAFE_BASIC_LABEL_UI = new BasicLabelUI(); + private static final Object BASIC_LABEL_UI_KEY = new Object(); private Rectangle paintIconR = new Rectangle(); private Rectangle paintTextR = new Rectangle(); @@ -394,10 +396,16 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener public static ComponentUI createUI(JComponent c) { if (System.getSecurityManager() != null) { - return SAFE_BASIC_LABEL_UI; - } else { - return labelUI; + AppContext appContext = AppContext.getAppContext(); + BasicLabelUI safeBasicLabelUI = + (BasicLabelUI) appContext.get(BASIC_LABEL_UI_KEY); + if (safeBasicLabelUI == null) { + safeBasicLabelUI = new BasicLabelUI(); + appContext.put(BASIC_LABEL_UI_KEY, safeBasicLabelUI); + } + return safeBasicLabelUI; } + return labelUI; } public void propertyChange(PropertyChangeEvent e) { diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java index be9d13204c7..1dc781645a6 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java @@ -32,6 +32,7 @@ import javax.swing.border.*; import javax.swing.plaf.*; import javax.swing.text.View; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; /** @@ -41,7 +42,7 @@ import sun.swing.SwingUtilities2; */ public class BasicRadioButtonUI extends BasicToggleButtonUI { - private final static BasicRadioButtonUI radioButtonUI = new BasicRadioButtonUI(); + private static final Object BASIC_RADIO_BUTTON_UI_KEY = new Object(); protected Icon icon; @@ -53,6 +54,13 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + BasicRadioButtonUI radioButtonUI = + (BasicRadioButtonUI) appContext.get(BASIC_RADIO_BUTTON_UI_KEY); + if (radioButtonUI == null) { + radioButtonUI = new BasicRadioButtonUI(); + appContext.put(BASIC_RADIO_BUTTON_UI_KEY, radioButtonUI); + } return radioButtonUI; } diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java index b35a75ed700..0be46948712 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -31,14 +31,12 @@ import sun.swing.DefaultLookup; import sun.swing.UIAction; import javax.swing.*; import javax.swing.border.Border; -import javax.swing.event.*; import java.awt.*; import java.awt.event.*; import java.awt.peer.ComponentPeer; import java.awt.peer.LightweightPeer; import java.beans.*; import java.util.*; -import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.SplitPaneUI; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; @@ -106,13 +104,13 @@ public class BasicSplitPaneUI extends SplitPaneUI * Keys to use for forward focus traversal when the JComponent is * managing focus. */ - private static Set managingFocusForwardTraversalKeys; + private Set managingFocusForwardTraversalKeys; /** * Keys to use for backward focus traversal when the JComponent is * managing focus. */ - private static Set managingFocusBackwardTraversalKeys; + private Set managingFocusBackwardTraversalKeys; /** @@ -675,7 +673,7 @@ public class BasicSplitPaneUI extends SplitPaneUI * @return increment via keyboard methods. */ int getKeyboardMoveIncrement() { - return KEYBOARD_DIVIDER_MOVE_OFFSET; + return 3; } /** diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java index e519d3202d9..07c2e47feec 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java @@ -25,6 +25,8 @@ package javax.swing.plaf.basic; +import sun.awt.AppContext; + import java.awt.*; import java.awt.event.*; @@ -43,7 +45,7 @@ import javax.swing.text.View; */ public class BasicToggleButtonUI extends BasicButtonUI { - private final static BasicToggleButtonUI toggleButtonUI = new BasicToggleButtonUI(); + private static final Object BASIC_TOGGLE_BUTTON_UI_KEY = new Object(); private final static String propertyPrefix = "ToggleButton" + "."; @@ -51,6 +53,13 @@ public class BasicToggleButtonUI extends BasicButtonUI { // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + BasicToggleButtonUI toggleButtonUI = + (BasicToggleButtonUI) appContext.get(BASIC_TOGGLE_BUTTON_UI_KEY); + if (toggleButtonUI == null) { + toggleButtonUI = new BasicToggleButtonUI(); + appContext.put(BASIC_TOGGLE_BUTTON_UI_KEY, toggleButtonUI); + } return toggleButtonUI; } diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/MetalBumps.java b/jdk/src/share/classes/javax/swing/plaf/metal/MetalBumps.java index 655393b43fd..ae3ad679121 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalBumps.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalBumps.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,9 @@ package javax.swing.plaf.metal; import java.awt.*; import java.awt.image.*; import javax.swing.*; -import java.io.*; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import sun.awt.AppContext; /** * Implements the bumps used throughout the Metal Look and Feel. @@ -49,19 +50,9 @@ class MetalBumps implements Icon { protected Color shadowColor; protected Color backColor; - protected static Vector buffers = new Vector(); + private static final Object METAL_BUMPS = new Object(); protected BumpBuffer buffer; - public MetalBumps( Dimension bumpArea ) { - this( bumpArea.width, bumpArea.height ); - } - - public MetalBumps( int width, int height ) { - this(width, height, MetalLookAndFeel.getPrimaryControlHighlight(), - MetalLookAndFeel.getPrimaryControlDarkShadow(), - MetalLookAndFeel.getPrimaryControlShadow()); - } - /** * Creates MetalBumps of the specified size with the specified colors. * If newBackColor is null, the background will be @@ -73,26 +64,22 @@ class MetalBumps implements Icon { setBumpColors( newTopColor, newShadowColor, newBackColor ); } - private BumpBuffer getBuffer(GraphicsConfiguration gc, Color aTopColor, - Color aShadowColor, Color aBackColor) { - if (buffer != null && buffer.hasSameConfiguration( - gc, aTopColor, aShadowColor, aBackColor)) { - return buffer; + private static BumpBuffer createBuffer(GraphicsConfiguration gc, + Color topColor, Color shadowColor, Color backColor) { + AppContext context = AppContext.getAppContext(); + List buffers = (List) context.get(METAL_BUMPS); + if (buffers == null) { + buffers = new ArrayList(); + context.put(METAL_BUMPS, buffers); } - BumpBuffer result = null; - - for (BumpBuffer aBuffer : buffers) { - if ( aBuffer.hasSameConfiguration(gc, aTopColor, aShadowColor, - aBackColor)) { - result = aBuffer; - break; + for (BumpBuffer buffer : buffers) { + if (buffer.hasSameConfiguration(gc, topColor, shadowColor, backColor)) { + return buffer; } } - if (result == null) { - result = new BumpBuffer(gc, topColor, shadowColor, backColor); - buffers.addElement(result); - } - return result; + BumpBuffer buffer = new BumpBuffer(gc, topColor, shadowColor, backColor); + buffers.add(buffer); + return buffer; } public void setBumpArea( Dimension bumpArea ) { @@ -119,10 +106,12 @@ class MetalBumps implements Icon { GraphicsConfiguration gc = (g instanceof Graphics2D) ? ((Graphics2D) g).getDeviceConfiguration() : null; - buffer = getBuffer(gc, topColor, shadowColor, backColor); + if ((buffer == null) || !buffer.hasSameConfiguration(gc, topColor, shadowColor, backColor)) { + buffer = createBuffer(gc, topColor, shadowColor, backColor); + } - int bufferWidth = buffer.getImageSize().width; - int bufferHeight = buffer.getImageSize().height; + int bufferWidth = BumpBuffer.IMAGE_SIZE; + int bufferHeight = BumpBuffer.IMAGE_SIZE; int iconWidth = getIconWidth(); int iconHeight = getIconHeight(); int x2 = x + iconWidth; @@ -155,7 +144,6 @@ class MetalBumps implements Icon { class BumpBuffer { static final int IMAGE_SIZE = 64; - static Dimension imageSize = new Dimension( IMAGE_SIZE, IMAGE_SIZE ); transient Image image; Color topColor; @@ -197,10 +185,6 @@ class BumpBuffer { return image; } - public Dimension getImageSize() { - return imageSize; - } - /** * Paints the bumps into the current image. */ diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/MetalButtonUI.java b/jdk/src/share/classes/javax/swing/plaf/metal/MetalButtonUI.java index 9917640cace..659315423fe 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalButtonUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalButtonUI.java @@ -26,6 +26,8 @@ package javax.swing.plaf.metal; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.border.*; import javax.swing.plaf.basic.*; @@ -49,19 +51,25 @@ import javax.swing.plaf.*; * @author Tom Santos */ public class MetalButtonUI extends BasicButtonUI { - - private final static MetalButtonUI metalButtonUI = new MetalButtonUI(); - // NOTE: These are not really needed, but at this point we can't pull // them. Their values are updated purely for historical reasons. protected Color focusColor; protected Color selectColor; protected Color disabledTextColor; + private static final Object METAL_BUTTON_UI_KEY = new Object(); + // ******************************** // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + MetalButtonUI metalButtonUI = + (MetalButtonUI) appContext.get(METAL_BUTTON_UI_KEY); + if (metalButtonUI == null) { + metalButtonUI = new MetalButtonUI(); + appContext.put(METAL_BUTTON_UI_KEY, metalButtonUI); + } return metalButtonUI; } diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/MetalCheckBoxUI.java b/jdk/src/share/classes/javax/swing/plaf/metal/MetalCheckBoxUI.java index a061ac078a6..650eda000e0 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalCheckBoxUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalCheckBoxUI.java @@ -25,6 +25,8 @@ package javax.swing.plaf.metal; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.plaf.basic.BasicCheckBoxUI; @@ -55,7 +57,7 @@ public class MetalCheckBoxUI extends MetalRadioButtonUI { // of BasicCheckBoxUI because we want to pick up all the // painting changes made in MetalRadioButtonUI. - private final static MetalCheckBoxUI checkboxUI = new MetalCheckBoxUI(); + private static final Object METAL_CHECK_BOX_UI_KEY = new Object(); private final static String propertyPrefix = "CheckBox" + "."; @@ -65,6 +67,13 @@ public class MetalCheckBoxUI extends MetalRadioButtonUI { // Create PlAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + MetalCheckBoxUI checkboxUI = + (MetalCheckBoxUI) appContext.get(METAL_CHECK_BOX_UI_KEY); + if (checkboxUI == null) { + checkboxUI = new MetalCheckBoxUI(); + appContext.put(METAL_CHECK_BOX_UI_KEY, checkboxUI); + } return checkboxUI; } diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameUI.java b/jdk/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameUI.java index d960ca19b75..adac940c4a4 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameUI.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. 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 @@ -31,10 +31,8 @@ import javax.swing.*; import javax.swing.event.*; import javax.swing.border.*; import javax.swing.plaf.basic.*; -import java.util.EventListener; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; -import java.beans.PropertyVetoException; import javax.swing.plaf.*; /** @@ -51,7 +49,7 @@ public class MetalInternalFrameUI extends BasicInternalFrameUI { private static final Border handyEmptyBorder = new EmptyBorder(0,0,0,0); protected static String IS_PALETTE = "JInternalFrame.isPalette"; - + private static String IS_PALETTE_KEY = "JInternalFrame.isPalette"; private static String FRAME_TYPE = "JInternalFrame.frameType"; private static String NORMAL_FRAME = "normal"; private static String PALETTE_FRAME = "palette"; @@ -68,7 +66,7 @@ public class MetalInternalFrameUI extends BasicInternalFrameUI { public void installUI(JComponent c) { super.installUI(c); - Object paletteProp = c.getClientProperty( IS_PALETTE ); + Object paletteProp = c.getClientProperty(IS_PALETTE_KEY); if ( paletteProp != null ) { setPalette( ((Boolean)paletteProp).booleanValue() ); } @@ -187,7 +185,7 @@ public class MetalInternalFrameUI extends BasicInternalFrameUI { ui.setFrameType( (String) e.getNewValue() ); } } - else if ( name.equals( IS_PALETTE ) ) + else if ( name.equals(IS_PALETTE_KEY) ) { if ( e.getNewValue() != null ) { diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/MetalLabelUI.java b/jdk/src/share/classes/javax/swing/plaf/metal/MetalLabelUI.java index f19fc9962ac..d4a341bea5d 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalLabelUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalLabelUI.java @@ -26,6 +26,8 @@ package javax.swing.plaf.metal; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.plaf.*; import javax.swing.plaf.basic.*; @@ -51,15 +53,21 @@ public class MetalLabelUI extends BasicLabelUI * name in defaults table under the key "LabelUI". */ protected static MetalLabelUI metalLabelUI = new MetalLabelUI(); - private final static MetalLabelUI SAFE_METAL_LABEL_UI = new MetalLabelUI(); + private static final Object METAL_LABEL_UI_KEY = new Object(); public static ComponentUI createUI(JComponent c) { if (System.getSecurityManager() != null) { - return SAFE_METAL_LABEL_UI; - } else { - return metalLabelUI; + AppContext appContext = AppContext.getAppContext(); + MetalLabelUI safeMetalLabelUI = + (MetalLabelUI) appContext.get(METAL_LABEL_UI_KEY); + if (safeMetalLabelUI == null) { + safeMetalLabelUI = new MetalLabelUI(); + appContext.put(METAL_LABEL_UI_KEY, safeMetalLabelUI); + } + return safeMetalLabelUI; } + return metalLabelUI; } /** diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java b/jdk/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java index 088daed9dd3..42a3703a670 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java @@ -26,6 +26,8 @@ package javax.swing.plaf.metal; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import java.awt.*; import java.awt.event.*; import javax.swing.*; @@ -53,7 +55,7 @@ import javax.swing.text.View; */ public class MetalRadioButtonUI extends BasicRadioButtonUI { - private static final MetalRadioButtonUI metalRadioButtonUI = new MetalRadioButtonUI(); + private static final Object METAL_RADIO_BUTTON_UI_KEY = new Object(); protected Color focusColor; protected Color selectColor; @@ -65,6 +67,13 @@ public class MetalRadioButtonUI extends BasicRadioButtonUI { // Create PlAF // ******************************** public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + MetalRadioButtonUI metalRadioButtonUI = + (MetalRadioButtonUI) appContext.get(METAL_RADIO_BUTTON_UI_KEY); + if (metalRadioButtonUI == null) { + metalRadioButtonUI = new MetalRadioButtonUI(); + appContext.put(METAL_RADIO_BUTTON_UI_KEY, metalRadioButtonUI); + } return metalRadioButtonUI; } diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java b/jdk/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java index 28d22705b16..da3d424e409 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. 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 @@ -54,12 +54,13 @@ public class MetalSliderUI extends BasicSliderUI { protected final int TICK_BUFFER = 4; protected boolean filledSlider = false; - // NOTE: these next three variables are currently unused. + // NOTE: these next five variables are currently unused. protected static Color thumbColor; protected static Color highlightColor; protected static Color darkShadowColor; protected static int trackWidth; protected static int tickLength; + private int safeLength; /** * A default horizontal thumb Icon. This field might not be @@ -107,7 +108,7 @@ public class MetalSliderUI extends BasicSliderUI { public void installUI( JComponent c ) { trackWidth = ((Integer)UIManager.get( "Slider.trackWidth" )).intValue(); - tickLength = ((Integer)UIManager.get( "Slider.majorTickLength" )).intValue(); + tickLength = safeLength = ((Integer)UIManager.get( "Slider.majorTickLength" )).intValue(); horizThumbIcon = SAFE_HORIZ_THUMB_ICON = UIManager.getIcon( "Slider.horizontalThumbIcon" ); vertThumbIcon = SAFE_VERT_THUMB_ICON = @@ -477,8 +478,8 @@ public class MetalSliderUI extends BasicSliderUI { * determine the tick area rectangle. */ public int getTickLength() { - return slider.getOrientation() == JSlider.HORIZONTAL ? tickLength + TICK_BUFFER + 1 : - tickLength + TICK_BUFFER + 3; + return slider.getOrientation() == JSlider.HORIZONTAL ? safeLength + TICK_BUFFER + 1 : + safeLength + TICK_BUFFER + 3; } /** @@ -523,22 +524,22 @@ public class MetalSliderUI extends BasicSliderUI { protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() ); - g.drawLine( x, TICK_BUFFER, x, TICK_BUFFER + (tickLength / 2) ); + g.drawLine( x, TICK_BUFFER, x, TICK_BUFFER + (safeLength / 2) ); } protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() ); - g.drawLine( x, TICK_BUFFER , x, TICK_BUFFER + (tickLength - 1) ); + g.drawLine( x, TICK_BUFFER , x, TICK_BUFFER + (safeLength - 1) ); } protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) { g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() ); if (MetalUtils.isLeftToRight(slider)) { - g.drawLine( TICK_BUFFER, y, TICK_BUFFER + (tickLength / 2), y ); + g.drawLine( TICK_BUFFER, y, TICK_BUFFER + (safeLength / 2), y ); } else { - g.drawLine( 0, y, tickLength/2, y ); + g.drawLine( 0, y, safeLength/2, y ); } } @@ -546,10 +547,10 @@ public class MetalSliderUI extends BasicSliderUI { g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() ); if (MetalUtils.isLeftToRight(slider)) { - g.drawLine( TICK_BUFFER, y, TICK_BUFFER + tickLength, y ); + g.drawLine( TICK_BUFFER, y, TICK_BUFFER + safeLength, y ); } else { - g.drawLine( 0, y, tickLength, y ); + g.drawLine( 0, y, safeLength, y ); } } } diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/MetalToggleButtonUI.java b/jdk/src/share/classes/javax/swing/plaf/metal/MetalToggleButtonUI.java index c6a8ce8ffcc..03b2454b819 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalToggleButtonUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalToggleButtonUI.java @@ -26,6 +26,8 @@ package javax.swing.plaf.metal; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import java.awt.*; import java.awt.event.*; import java.lang.ref.*; @@ -55,7 +57,7 @@ import java.io.Serializable; */ public class MetalToggleButtonUI extends BasicToggleButtonUI { - private static final MetalToggleButtonUI metalToggleButtonUI = new MetalToggleButtonUI(); + private static final Object METAL_TOGGLE_BUTTON_UI_KEY = new Object(); protected Color focusColor; protected Color selectColor; @@ -67,6 +69,13 @@ public class MetalToggleButtonUI extends BasicToggleButtonUI { // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + MetalToggleButtonUI metalToggleButtonUI = + (MetalToggleButtonUI) appContext.get(METAL_TOGGLE_BUTTON_UI_KEY); + if (metalToggleButtonUI == null) { + metalToggleButtonUI = new MetalToggleButtonUI(); + appContext.put(METAL_TOGGLE_BUTTON_UI_KEY, metalToggleButtonUI); + } return metalToggleButtonUI; } diff --git a/jdk/src/share/classes/sun/applet/AppletClassLoader.java b/jdk/src/share/classes/sun/applet/AppletClassLoader.java index 3489256ae4a..0eeba1582dd 100644 --- a/jdk/src/share/classes/sun/applet/AppletClassLoader.java +++ b/jdk/src/share/classes/sun/applet/AppletClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2009 Sun Microsystems, Inc. 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 @@ -51,6 +51,7 @@ import java.security.Permission; import java.security.PermissionCollection; import sun.awt.AppContext; import sun.awt.SunToolkit; +import sun.misc.IOUtils; import sun.net.www.ParseUtil; import sun.security.util.SecurityConstants; @@ -331,36 +332,7 @@ public class AppletClassLoader extends URLClassLoader { byte[] b; try { - if (len != -1) { - // Read exactly len bytes from the input stream - b = new byte[len]; - while (len > 0) { - int n = in.read(b, b.length - len, len); - if (n == -1) { - throw new IOException("unexpected EOF"); - } - len -= n; - } - } else { - // Read until end of stream is reached - use 8K buffer - // to speed up performance [stanleyh] - b = new byte[8192]; - int total = 0; - while ((len = in.read(b, total, b.length - total)) != -1) { - total += len; - if (total >= b.length) { - byte[] tmp = new byte[total * 2]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } - // Trim array to correct size, if necessary - if (total != b.length) { - byte[] tmp = new byte[total]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } + b = IOUtils.readFully(in, len, true); } finally { in.close(); } diff --git a/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java b/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java index ca9260b5a8c..1f034ea6e17 100644 --- a/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java +++ b/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java @@ -336,10 +336,6 @@ public class ImageRepresentation extends ImageWatched implements ImageConsumer public native void setICMpixels(int x, int y, int w, int h, int[] lut, byte[] pix, int off, int scansize, IntegerComponentRaster ict); - - public native void setBytePixels(int x, int y, int w, int h, byte[] pix, - int off, int scansize, - ByteComponentRaster bct, int chanOff); public native int setDiffICM(int x, int y, int w, int h, int[] lut, int transPix, int numLut, IndexColorModel icm, byte[] pix, int off, int scansize, @@ -450,27 +446,17 @@ public class ImageRepresentation extends ImageWatched implements ImageConsumer (biRaster instanceof ByteComponentRaster) && (biRaster.getNumDataElements() == 1)){ ByteComponentRaster bt = (ByteComponentRaster) biRaster; - if (w*h > 200) { - if (off == 0 && scansize == w) { - bt.putByteData(x, y, w, h, pix); - } - else { - byte[] bpix = new byte[w]; - poff = off; - for (int yoff=y; yoff < y+h; yoff++) { - System.arraycopy(pix, poff, bpix, 0, w); - bt.putByteData(x, yoff, w, 1, bpix); - poff += scansize; - } - } + if (off == 0 && scansize == w) { + bt.putByteData(x, y, w, h, pix); } else { - // Only is faster if #pixels - // Note that setBytePixels modifies the raster directly - // so we must mark it as changed afterwards - setBytePixels(x, y, w, h, pix, off, scansize, bt, - bt.getDataOffset(0)); - bt.markDirty(); + byte[] bpix = new byte[w]; + poff = off; + for (int yoff=y; yoff < y+h; yoff++) { + System.arraycopy(pix, poff, bpix, 0, w); + bt.putByteData(x, yoff, w, 1, bpix); + poff += scansize; + } } } else { diff --git a/jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java b/jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java index a182161271b..5515d93c423 100644 --- a/jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java +++ b/jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java @@ -26,9 +26,9 @@ package sun.dyn.anon; import java.io.IOException; -import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import sun.misc.IOUtils; /** * Anonymous class loader. Will load any valid classfile, producing @@ -285,13 +285,6 @@ public class AnonymousClassLoader { if (contentLength < 0) throw new IOException("invalid content length "+contentLength); - byte[] classFile = new byte[contentLength]; - InputStream tcs = connection.getInputStream(); - for (int fill = 0, nr; fill < classFile.length; fill += nr) { - nr = tcs.read(classFile, fill, classFile.length - fill); - if (nr < 0) - throw new IOException("premature end of file"); - } - return classFile; + return IOUtils.readFully(connection.getInputStream(), contentLength, true); } } diff --git a/jdk/src/share/classes/sun/misc/IOUtils.java b/jdk/src/share/classes/sun/misc/IOUtils.java new file mode 100644 index 00000000000..c6f4fb2a13b --- /dev/null +++ b/jdk/src/share/classes/sun/misc/IOUtils.java @@ -0,0 +1,80 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * IOUtils: A collection of IO-related public static methods. + */ + +package sun.misc; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +public class IOUtils { + + /** + * Read up to length of bytes from in + * until EOF is detected. + * @param in input stream, must not be null + * @param length number of bytes to read, -1 or Integer.MAX_VALUE means + * read as much as possible + * @param readAll if true, an EOFException will be thrown if not enough + * bytes are read. Ignored when length is -1 or Integer.MAX_VALUE + * @return bytes read + * @throws IOException Any IO error or a premature EOF is detected + */ + public static byte[] readFully(InputStream is, int length, boolean readAll) + throws IOException { + byte[] output = {}; + if (length == -1) length = Integer.MAX_VALUE; + int pos = 0; + while (pos < length) { + int bytesToRead; + if (pos >= output.length) { // Only expand when there's no room + bytesToRead = Math.min(length - pos, output.length + 1024); + if (output.length < pos + bytesToRead) { + output = Arrays.copyOf(output, pos + bytesToRead); + } + } else { + bytesToRead = output.length - pos; + } + int cc = is.read(output, pos, bytesToRead); + if (cc < 0) { + if (readAll && length != Integer.MAX_VALUE) { + throw new EOFException("Detect premature EOF"); + } else { + if (output.length != pos) { + output = Arrays.copyOf(output, pos); + } + break; + } + } + pos += cc; + } + return output; + } +} diff --git a/jdk/src/share/classes/sun/misc/Resource.java b/jdk/src/share/classes/sun/misc/Resource.java index 0c3579bc334..43a82b03a70 100644 --- a/jdk/src/share/classes/sun/misc/Resource.java +++ b/jdk/src/share/classes/sun/misc/Resource.java @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. 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,14 +25,15 @@ package sun.misc; +import java.io.EOFException; import java.net.URL; import java.io.IOException; import java.io.InterruptedIOException; import java.io.InputStream; import java.security.CodeSigner; import java.util.jar.Manifest; -import java.util.jar.Attributes; import java.nio.ByteBuffer; +import java.util.Arrays; import sun.nio.ByteBuffered; /** @@ -105,49 +106,37 @@ public abstract class Resource { } try { - if (len != -1) { - // Read exactly len bytes from the input stream - b = new byte[len]; - while (len > 0) { - int n = 0; - try { - n = in.read(b, b.length - len, len); - } catch (InterruptedIOException iioe) { - Thread.interrupted(); - isInterrupted = true; + b = new byte[0]; + if (len == -1) len = Integer.MAX_VALUE; + int pos = 0; + while (pos < len) { + int bytesToRead; + if (pos >= b.length) { // Only expand when there's no room + bytesToRead = Math.min(len - pos, b.length + 1024); + if (b.length < pos + bytesToRead) { + b = Arrays.copyOf(b, pos + bytesToRead); } - if (n == -1) { - throw new IOException("unexpected EOF"); - } - len -= n; + } else { + bytesToRead = b.length - pos; } - } else { - // Read until end of stream is reached - b = new byte[1024]; - int total = 0; - for (;;) { - len = 0; - try { - len = in.read(b, total, b.length - total); - if (len == -1) - break; - } catch (InterruptedIOException iioe) { - Thread.interrupted(); - isInterrupted = true; - } - total += len; - if (total >= b.length) { - byte[] tmp = new byte[total * 2]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; + int cc = 0; + try { + cc = in.read(b, pos, bytesToRead); + } catch (InterruptedIOException iioe) { + Thread.interrupted(); + isInterrupted = true; + } + if (cc < 0) { + if (len != Integer.MAX_VALUE) { + throw new EOFException("Detect premature EOF"); + } else { + if (b.length != pos) { + b = Arrays.copyOf(b, pos); + } + break; } } - // Trim array to correct size, if necessary - if (total != b.length) { - byte[] tmp = new byte[total]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } + pos += cc; } } finally { try { diff --git a/jdk/src/share/classes/sun/misc/Version-template.java b/jdk/src/share/classes/sun/misc/Version.java.template similarity index 100% rename from jdk/src/share/classes/sun/misc/Version-template.java rename to jdk/src/share/classes/sun/misc/Version.java.template diff --git a/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java b/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java index 09b14f521d1..39fa2d8afe9 100644 --- a/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java +++ b/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import java.lang.reflect.Modifier; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import sun.misc.IOUtils; import sun.net.www.ParseUtil; import sun.security.util.SecurityConstants; @@ -373,34 +374,7 @@ public final class MethodUtil extends SecureClassLoader { byte[] b; try { - if (len != -1) { - // Read exactly len bytes from the input stream - b = new byte[len]; - while (len > 0) { - int n = in.read(b, b.length - len, len); - if (n == -1) { - throw new IOException("unexpected EOF"); - } - len -= n; - } - } else { - b = new byte[8192]; - int total = 0; - while ((len = in.read(b, total, b.length - total)) != -1) { - total += len; - if (total >= b.length) { - byte[] tmp = new byte[total * 2]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } - // Trim array to correct size, if necessary - if (total != b.length) { - byte[] tmp = new byte[total]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } + b = IOUtils.readFully(in, len, true); } finally { in.close(); } diff --git a/jdk/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java b/jdk/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java new file mode 100644 index 00000000000..0921351863e --- /dev/null +++ b/jdk/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java @@ -0,0 +1,119 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.security.provider.certpath; + +import java.util.Set; +import java.util.Collection; +import java.util.Locale; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.cert.X509CRL; +import java.security.cert.CertPathValidatorException; +import java.security.cert.PKIXCertPathChecker; + +import sun.security.x509.AlgorithmId; + +/** + * AlgorithmChecker is a PKIXCertPathChecker that checks that + * the signature algorithm of the specified certificate is not disabled. + * + * @author Xuelei Fan + */ +final public class AlgorithmChecker extends PKIXCertPathChecker { + + // the disabled algorithms + private static final String[] disabledAlgorithms = new String[] {"md2"}; + + // singleton instance + static final AlgorithmChecker INSTANCE = new AlgorithmChecker(); + + /** + * Default Constructor + */ + private AlgorithmChecker() { + // do nothing + } + + /** + * Return a AlgorithmChecker instance. + */ + static AlgorithmChecker getInstance() { + return INSTANCE; + } + + /** + * Initializes the internal state of the checker from parameters + * specified in the constructor. + */ + public void init(boolean forward) throws CertPathValidatorException { + // do nothing + } + + public boolean isForwardCheckingSupported() { + return false; + } + + public Set getSupportedExtensions() { + return null; + } + + /** + * Checks the signature algorithm of the specified certificate. + */ + public void check(Certificate cert, Collection unresolvedCritExts) + throws CertPathValidatorException { + check(cert); + } + + public static void check(Certificate cert) + throws CertPathValidatorException { + X509Certificate xcert = (X509Certificate)cert; + check(xcert.getSigAlgName()); + } + + static void check(AlgorithmId aid) throws CertPathValidatorException { + check(aid.getName()); + } + + static void check(X509CRL crl) throws CertPathValidatorException { + check(crl.getSigAlgName()); + } + + private static void check(String algName) + throws CertPathValidatorException { + + String lowerCaseAlgName = algName.toLowerCase(Locale.ENGLISH); + + for (String disabled : disabledAlgorithms) { + // checking the signature algorithm name + if (lowerCaseAlgName.indexOf(disabled) != -1) { + throw new CertPathValidatorException( + "algorithm check failed: " + algName + " is disabled"); + } + } + } + +} diff --git a/jdk/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/jdk/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java index dea521a4a19..f1005ac7e3b 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java @@ -289,6 +289,16 @@ class DistributionPointFetcher { X500Name certIssuer = (X500Name) certImpl.getIssuerDN(); X500Name crlIssuer = (X500Name) crlImpl.getIssuerDN(); + // check the crl signature algorithm + try { + AlgorithmChecker.check(crl); + } catch (CertPathValidatorException cpve) { + if (debug != null) { + debug.println("CRL signature algorithm check failed: " + cpve); + } + return false; + } + // if crlIssuer is set, verify that it matches the issuer of the // CRL and the CRL contains an IDP extension with the indirectCRL // boolean asserted. Otherwise, verify that the CRL issuer matches the diff --git a/jdk/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/jdk/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java index 41fe50d66b7..59ce3a9713c 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java @@ -718,6 +718,11 @@ class ForwardBuilder extends Builder { /* we don't perform any validation of the trusted cert */ if (!isTrustedCert) { + /* + * check that the signature algorithm is not disabled. + */ + AlgorithmChecker.check(cert); + /* * Check CRITICAL private extensions for user checkers that * support forward checking (forwardCheckers) and remove diff --git a/jdk/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java b/jdk/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java index 145879239ac..8dab2f3b26c 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java @@ -275,6 +275,7 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { int certPathLen = certList.size(); basicChecker = new BasicChecker(anchor, testDate, sigProvider, false); + AlgorithmChecker algorithmChecker= AlgorithmChecker.getInstance(); KeyChecker keyChecker = new KeyChecker(certPathLen, pkixParam.getTargetCertConstraints()); ConstraintsChecker constraintsChecker = @@ -291,6 +292,7 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ArrayList certPathCheckers = new ArrayList(); // add standard checkers that we will be using + certPathCheckers.add(algorithmChecker); certPathCheckers.add(keyChecker); certPathCheckers.add(constraintsChecker); certPathCheckers.add(policyChecker); diff --git a/jdk/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java b/jdk/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java index 6f826026caf..c8762ef7447 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. 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 @@ -347,6 +347,9 @@ class ReverseBuilder extends Builder { return; } + /* check that the signature algorithm is not disabled. */ + AlgorithmChecker.check(cert); + /* * check for looping - abort a loop if * ((we encounter the same certificate twice) AND diff --git a/jdk/src/share/classes/sun/security/timestamp/HttpTimestamper.java b/jdk/src/share/classes/sun/security/timestamp/HttpTimestamper.java index bb735141159..04c0b67ee82 100644 --- a/jdk/src/share/classes/sun/security/timestamp/HttpTimestamper.java +++ b/jdk/src/share/classes/sun/security/timestamp/HttpTimestamper.java @@ -34,6 +34,7 @@ import java.util.Iterator; import java.util.Set; import java.util.Arrays; +import sun.misc.IOUtils; import sun.security.pkcs.*; /** @@ -142,25 +143,7 @@ public class HttpTimestamper implements Timestamper { int total = 0; int contentLength = connection.getContentLength(); - if (contentLength != -1) { - replyBuffer = new byte[contentLength]; - } else { - replyBuffer = new byte[2048]; - contentLength = Integer.MAX_VALUE; - } - - while (total < contentLength) { - int count = input.read(replyBuffer, total, - replyBuffer.length - total); - if (count < 0) - break; - - total += count; - if (total >= replyBuffer.length && total < contentLength) { - replyBuffer = Arrays.copyOf(replyBuffer, total * 2); - } - } - replyBuffer = Arrays.copyOf(replyBuffer, total); + replyBuffer = IOUtils.readFully(input, contentLength, false); if (DEBUG) { System.out.println("received timestamp response (length=" + diff --git a/jdk/src/share/classes/sun/security/util/DerValue.java b/jdk/src/share/classes/sun/security/util/DerValue.java index 114788beb26..c0f920d5e33 100644 --- a/jdk/src/share/classes/sun/security/util/DerValue.java +++ b/jdk/src/share/classes/sun/security/util/DerValue.java @@ -28,6 +28,7 @@ package sun.security.util; import java.io.*; import java.math.BigInteger; import java.util.Date; +import sun.misc.IOUtils; /** * Represents a single DER-encoded value. DER encoding rules are a subset @@ -382,12 +383,8 @@ public class DerValue { if (fullyBuffered && in.available() != length) throw new IOException("extra data given to DerValue constructor"); - byte[] bytes = new byte[length]; + byte[] bytes = IOUtils.readFully(in, length, true); - // n.b. readFully not needed in normal fullyBuffered case - DataInputStream dis = new DataInputStream(in); - - dis.readFully(bytes); buffer = new DerInputBuffer(bytes); return new DerInputStream(buffer); } diff --git a/jdk/src/share/classes/sun/security/validator/SimpleValidator.java b/jdk/src/share/classes/sun/security/validator/SimpleValidator.java index d21466a608b..eff9045c2f6 100644 --- a/jdk/src/share/classes/sun/security/validator/SimpleValidator.java +++ b/jdk/src/share/classes/sun/security/validator/SimpleValidator.java @@ -40,6 +40,8 @@ import sun.security.util.DerInputStream; import sun.security.util.DerOutputStream; import sun.security.util.ObjectIdentifier; +import sun.security.provider.certpath.AlgorithmChecker; + /** * A simple validator implementation. It is based on code from the JSSE * X509TrustManagerImpl. This implementation is designed for compatibility with @@ -134,6 +136,13 @@ public final class SimpleValidator extends Validator { X509Certificate issuerCert = chain[i + 1]; X509Certificate cert = chain[i]; + // check certificate algorithm + try { + AlgorithmChecker.check(cert); + } catch (CertPathValidatorException cpve) { + throw new ValidatorException + (ValidatorException.T_ALGORITHM_DISABLED, cert, cpve); + } // no validity check for code signing certs if ((variant.equals(VAR_CODE_SIGNING) == false) diff --git a/jdk/src/share/classes/sun/security/validator/ValidatorException.java b/jdk/src/share/classes/sun/security/validator/ValidatorException.java index 67f42cfa472..53b8667f29f 100644 --- a/jdk/src/share/classes/sun/security/validator/ValidatorException.java +++ b/jdk/src/share/classes/sun/security/validator/ValidatorException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2009 Sun Microsystems, Inc. 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 @@ -55,6 +55,9 @@ public class ValidatorException extends CertificateException { public final static Object T_NAME_CHAINING = "Certificate chaining error"; + public final static Object T_ALGORITHM_DISABLED = + "Certificate signature algorithm disabled"; + private Object type; private X509Certificate cert; diff --git a/jdk/src/share/classes/sun/text/bidi/BidiBase.java b/jdk/src/share/classes/sun/text/bidi/BidiBase.java index be494ea3cc8..ccc020de7b9 100644 --- a/jdk/src/share/classes/sun/text/bidi/BidiBase.java +++ b/jdk/src/share/classes/sun/text/bidi/BidiBase.java @@ -52,10 +52,11 @@ package sun.text.bidi; -import java.awt.font.TextAttribute; -import java.awt.font.NumericShaper; import java.io.IOException; import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; import java.text.AttributedCharacterIterator; import java.text.Bidi; import java.util.Arrays; @@ -2689,12 +2690,13 @@ public class BidiBase { public void setPara(AttributedCharacterIterator paragraph) { byte paraLvl; - Boolean runDirection = (Boolean) paragraph.getAttribute(TextAttribute.RUN_DIRECTION); - NumericShaper shaper = (NumericShaper) paragraph.getAttribute(TextAttribute.NUMERIC_SHAPING); + Boolean runDirection = + (Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION); + Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING); if (runDirection == null) { paraLvl = INTERNAL_LEVEL_DEFAULT_LTR; } else { - paraLvl = (runDirection.equals(TextAttribute.RUN_DIRECTION_LTR)) ? + paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ? (byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT; } @@ -2706,7 +2708,8 @@ public class BidiBase { char ch = paragraph.first(); while (ch != AttributedCharacterIterator.DONE) { txt[i] = ch; - Integer embedding = (Integer) paragraph.getAttribute(TextAttribute.BIDI_EMBEDDING); + Integer embedding = + (Integer) paragraph.getAttribute(TextAttributeConstants.BIDI_EMBEDDING); if (embedding != null) { byte level = embedding.byteValue(); if (level == 0) { @@ -2724,7 +2727,7 @@ public class BidiBase { } if (shaper != null) { - shaper.shape(txt, 0, len); + NumericShapings.shape(shaper, txt, 0, len); } setPara(txt, paraLvl, lvls); } @@ -3441,4 +3444,106 @@ public class BidiBase { return buf.toString(); } + /** + * A class that provides access to constants defined by + * java.awt.font.TextAttribute without creating a static dependency. + */ + private static class TextAttributeConstants { + private static final Class clazz = getClass("java.awt.font.TextAttribute"); + + /** + * TextAttribute instances (or a fake Attribute type if + * java.awt.font.TextAttribute is not present) + */ + static final AttributedCharacterIterator.Attribute RUN_DIRECTION = + getTextAttribute("RUN_DIRECTION"); + static final Boolean RUN_DIRECTION_LTR = + (Boolean)getStaticField(clazz, "RUN_DIRECTION_LTR"); + static final AttributedCharacterIterator.Attribute NUMERIC_SHAPING = + getTextAttribute("NUMERIC_SHAPING"); + static final AttributedCharacterIterator.Attribute BIDI_EMBEDDING = + getTextAttribute("BIDI_EMBEDDING"); + + private static Class getClass(String name) { + try { + return Class.forName(name, true, null); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static Object getStaticField(Class clazz, String name) { + if (clazz == null) { + // fake attribute + return new AttributedCharacterIterator.Attribute(name) { }; + } else { + try { + Field f = clazz.getField(name); + return f.get(null); + } catch (NoSuchFieldException x) { + throw new AssertionError(x); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } + } + } + + private static AttributedCharacterIterator.Attribute + getTextAttribute(String name) + { + return (AttributedCharacterIterator.Attribute)getStaticField(clazz, name); + } + } + + /** + * A class that provides access to java.awt.font.NumericShaping without + * creating a static dependency. + */ + private static class NumericShapings { + private static final Class clazz = + getClass("java.awt.font.NumericShaper"); + private static final Method shapeMethod = + getMethod(clazz, "shape", char[].class, int.class, int.class); + + private static Class getClass(String name) { + try { + return Class.forName(name, true, null); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static Method getMethod(Class clazz, + String name, + Class... paramTypes) + { + if (clazz != null) { + try { + return clazz.getMethod(name, paramTypes); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } else { + return null; + } + } + + /** + * Invokes NumericShaping shape(text,start,count) method. + */ + static void shape(Object shaper, char[] text, int start, int count) { + if (shapeMethod == null) + throw new AssertionError("Should not get here"); + try { + shapeMethod.invoke(shaper, text, start, count); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException) + throw (RuntimeException)cause; + throw new AssertionError(e); + } catch (IllegalAccessException iae) { + throw new AssertionError(iae); + } + } + } } diff --git a/jdk/src/share/classes/sun/tools/jconsole/Version-template.java b/jdk/src/share/classes/sun/tools/jconsole/Version.java.template similarity index 100% rename from jdk/src/share/classes/sun/tools/jconsole/Version-template.java rename to jdk/src/share/classes/sun/tools/jconsole/Version.java.template diff --git a/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java b/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java index 6ada1afbbb6..52ec7099c51 100644 --- a/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. 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 @@ -472,6 +472,18 @@ public class ZoneInfoFile { private static Map zoneInfoObjects = null; + private static final String ziDir; + static { + String zi = (String) AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("java.home")) + + File.separator + "lib" + File.separator + "zi"; + try { + zi = new File(zi).getCanonicalPath(); + } catch (Exception e) { + } + ziDir = zi; + } + /** * Converts the given time zone ID to a platform dependent path * name. For example, "America/Los_Angeles" is converted to @@ -576,20 +588,7 @@ public class ZoneInfoFile { return null; } - int index; - for (index = 0; index < JAVAZI_LABEL.length; index++) { - if (buf[index] != JAVAZI_LABEL[index]) { - System.err.println("ZoneInfo: wrong magic number: " + id); - return null; - } - } - - if (buf[index++] > JAVAZI_VERSION) { - System.err.println("ZoneInfo: incompatible version (" - + buf[index - 1] + "): " + id); - return null; - } - + int index = 0; int filesize = buf.length; int rawOffset = 0; int dstSavings = 0; @@ -600,6 +599,18 @@ public class ZoneInfoFile { int[] simpleTimeZoneParams = null; try { + for (index = 0; index < JAVAZI_LABEL.length; index++) { + if (buf[index] != JAVAZI_LABEL[index]) { + System.err.println("ZoneInfo: wrong magic number: " + id); + return null; + } + } + if (buf[index++] > JAVAZI_VERSION) { + System.err.println("ZoneInfo: incompatible version (" + + buf[index - 1] + "): " + id); + return null; + } + while (index < filesize) { byte tag = buf[index++]; int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); @@ -1017,30 +1028,33 @@ public class ZoneInfoFile { * Reads the specified file under <java.home>/lib/zi into a buffer. * @return the buffer, or null if any I/O error occurred. */ - private static byte[] readZoneInfoFile(String fileName) { + private static byte[] readZoneInfoFile(final String fileName) { byte[] buffer = null; try { - String homeDir = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("java.home")); - final String fname = homeDir + File.separator + "lib" + File.separator - + "zi" + File.separator + fileName; buffer = (byte[]) AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws IOException { - File file = new File(fname); - if (!file.canRead()) { + File file = new File(ziDir, fileName); + if (!file.exists() || !file.isFile()) { return null; } - int filesize = (int)file.length(); - byte[] buf = new byte[filesize]; - - FileInputStream fis = new FileInputStream(file); - - if (fis.read(buf) != filesize) { - fis.close(); - throw new IOException("read error on " + fname); + file = file.getCanonicalFile(); + String path = file.getCanonicalPath(); + byte[] buf = null; + if (path != null && path.startsWith(ziDir)) { + int filesize = (int)file.length(); + if (filesize > 0) { + FileInputStream fis = new FileInputStream(file); + buf = new byte[filesize]; + try { + if (fis.read(buf) != filesize) { + throw new IOException("read error on " + fileName); + } + } finally { + fis.close(); + } + } } - fis.close(); return buf; } }); diff --git a/jdk/src/share/native/com/sun/media/sound/SoundDefs.h b/jdk/src/share/native/com/sun/media/sound/SoundDefs.h index 893dacf3e55..13dd33d4715 100644 --- a/jdk/src/share/native/com/sun/media/sound/SoundDefs.h +++ b/jdk/src/share/native/com/sun/media/sound/SoundDefs.h @@ -38,6 +38,7 @@ #define X_SPARCV9 3 #define X_IA64 4 #define X_AMD64 5 +#define X_ZERO 6 // ********************************** // Make sure you set X_PLATFORM and X_ARCH defines correctly. diff --git a/jdk/src/share/native/sun/awt/image/awt_ImageRep.c b/jdk/src/share/native/sun/awt/image/awt_ImageRep.c index 9017ee9520f..b40eec8944c 100644 --- a/jdk/src/share/native/sun/awt/image/awt_ImageRep.c +++ b/jdk/src/share/native/sun/awt/image/awt_ImageRep.c @@ -142,84 +142,6 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls, } -JNIEXPORT void JNICALL -Java_sun_awt_image_ImageRepresentation_setBytePixels(JNIEnv *env, jclass cls, - jint x, jint y, jint w, - jint h, jbyteArray jpix, - jint off, jint scansize, - jobject jbct, - jint chanOffs) -{ - int sStride; - int pixelStride; - jobject jdata; - unsigned char *srcData; - unsigned char *dstData; - unsigned char *dataP; - unsigned char *pixP; - int i; - int j; - - - if (JNU_IsNull(env, jpix)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - - sStride = (*env)->GetIntField(env, jbct, g_BCRscanstrID); - pixelStride = (*env)->GetIntField(env, jbct, g_BCRpixstrID); - jdata = (*env)->GetObjectField(env, jbct, g_BCRdataID); - - srcData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jpix, - NULL); - if (srcData == NULL) { - /* out of memory error already thrown */ - return; - } - - dstData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jdata, - NULL); - if (dstData == NULL) { - /* out of memory error already thrown */ - (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - return; - } - - dataP = dstData + chanOffs + y*sStride + x*pixelStride; - pixP = srcData + off; - if (pixelStride == 1) { - if (sStride == scansize && scansize == w) { - memcpy(dataP, pixP, w*h); - } - else { - for (i=0; i < h; i++) { - memcpy(dataP, pixP, w); - dataP += sStride; - pixP += scansize; - } - } - } - else { - unsigned char *ydataP = dataP; - unsigned char *ypixP = pixP; - - for (i=0; i < h; i++) { - dataP = ydataP; - pixP = ypixP; - for (j=0; j < w; j++) { - *dataP = *pixP++; - dataP += pixelStride; - } - ydataP += sStride; - ypixP += scansize; - } - } - - (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT); - -} - JNIEXPORT jint JNICALL Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, jint x, jint y, jint w, @@ -266,6 +188,13 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, jnewlut = (*env)->GetObjectField(env, jicm, g_ICMrgbID); mapSize = (*env)->GetIntField(env, jicm, g_ICMmapSizeID); + if (numLut < 0 || numLut > 256 || mapSize < 0 || mapSize > 256) { + /* Ether old or new ICM has a palette that exceeds capacity + of byte data type, so we have to convert the image data + to default representation. + */ + return 0; + } srcLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jlut, NULL); if (srcLUT == NULL) { diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index 7d39c61e02f..3897ddc86c6 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -676,6 +676,10 @@ static int setQTables(JNIEnv *env, #ifdef DEBUG_IIO_JPEG printf("in setQTables, qlen = %d, write is %d\n", qlen, write); #endif + if (qlen > NUM_QUANT_TBLS) { + /* Ignore extra qunterization tables. */ + qlen = NUM_QUANT_TBLS; + } for (i = 0; i < qlen; i++) { table = (*env)->GetObjectArrayElement(env, qtables, i); qdata = (*env)->GetObjectField(env, table, JPEGQTable_tableID); @@ -727,6 +731,11 @@ static void setHuffTable(JNIEnv *env, hlensBody = (*env)->GetShortArrayElements(env, huffLens, NULL); + if (hlensLen > 16) { + /* Ignore extra elements of bits array. Only 16 elements can be + stored. 0-th element is not used. (see jpeglib.h, line 107) */ + hlensLen = 16; + } for (i = 1; i <= hlensLen; i++) { huff_ptr->bits[i] = (UINT8)hlensBody[i-1]; } @@ -743,6 +752,11 @@ static void setHuffTable(JNIEnv *env, huffValues, NULL); + if (hvalsLen > 256) { + /* Ignore extra elements of hufval array. Only 256 elements + can be stored. (see jpeglib.h, line 109) */ + hlensLen = 256; + } for (i = 0; i < hvalsLen; i++) { huff_ptr->huffval[i] = (UINT8)hvalsBody[i]; } @@ -763,6 +777,11 @@ static int setHTables(JNIEnv *env, j_compress_ptr comp; j_decompress_ptr decomp; jsize hlen = (*env)->GetArrayLength(env, DCHuffmanTables); + + if (hlen > NUM_HUFF_TBLS) { + /* Ignore extra DC huffman tables. */ + hlen = NUM_HUFF_TBLS; + } for (i = 0; i < hlen; i++) { if (cinfo->is_decompressor) { decomp = (j_decompress_ptr) cinfo; @@ -784,6 +803,10 @@ static int setHTables(JNIEnv *env, huff_ptr->sent_table = !write; } hlen = (*env)->GetArrayLength(env, ACHuffmanTables); + if (hlen > NUM_HUFF_TBLS) { + /* Ignore extra AC huffman tables. */ + hlen = NUM_HUFF_TBLS; + } for (i = 0; i < hlen; i++) { if (cinfo->is_decompressor) { decomp = (j_decompress_ptr) cinfo; @@ -1833,6 +1856,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage return JNI_FALSE; } + if (stepX > cinfo->image_width) { + stepX = cinfo->image_width; + } + if (stepY > cinfo->image_height) { + stepY = cinfo->image_height; + } + /* * First get the source bands array and copy it to our local array * so we don't have to worry about pinning and unpinning it again. diff --git a/jdk/src/solaris/bin/ergo_zero.c b/jdk/src/solaris/bin/ergo_zero.c new file mode 100644 index 00000000000..3bf541444ca --- /dev/null +++ b/jdk/src/solaris/bin/ergo_zero.c @@ -0,0 +1,58 @@ +/* + * Copyright 1998-2007 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +#include "ergo.h" + + +/* Methods for solaris-sparc and linux-sparc: these are easy. */ + +/* Ask the OS how many processors there are. */ +static unsigned long +physical_processors(void) { + const unsigned long sys_processors = sysconf(_SC_NPROCESSORS_CONF); + + JLI_TraceLauncher("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors); + return sys_processors; +} + +/* The sparc version of the "server-class" predicate. */ +jboolean +ServerClassMachineImpl(void) { + jboolean result = JNI_FALSE; + /* How big is a server class machine? */ + const unsigned long server_processors = 2UL; + const uint64_t server_memory = 2UL * GB; + const uint64_t actual_memory = physical_memory(); + + /* Is this a server class machine? */ + if (actual_memory >= server_memory) { + const unsigned long actual_processors = physical_processors(); + if (actual_processors >= server_processors) { + result = JNI_TRUE; + } + } + JLI_TraceLauncher("unix_" LIBARCHNAME "_ServerClassMachine: %s\n", + (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE")); + return result; +} diff --git a/jdk/make/tools/fontchecker/Makefile b/jdk/src/solaris/bin/zero/jvm.cfg similarity index 66% rename from jdk/make/tools/fontchecker/Makefile rename to jdk/src/solaris/bin/zero/jvm.cfg index 1ed0f5d34c7..e4cea1c357b 100644 --- a/jdk/make/tools/fontchecker/Makefile +++ b/jdk/src/solaris/bin/zero/jvm.cfg @@ -1,5 +1,4 @@ -# -# Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003 Sun Microsystems, Inc. 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 @@ -22,22 +21,19 @@ # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. # - +# +# List of JVMs that can be used as an option to java, javac, etc. +# Order is important -- first in this list is the default JVM. +# NOTE that this both this file and its format are UNSUPPORTED and +# WILL GO AWAY in a future release. # -# Makefile for building the fontchecker tool +# You may also select a JVM in an arbitrary location with the +# "-XXaltjvm=" option, but that too is unsupported +# and may not be available in a future release. # - -BUILDDIR = ../.. -PACKAGE = build.tools.fontchecker -PRODUCT = tools -PROGRAM = fontchecker -include $(BUILDDIR)/common/Defs.gmk - -BUILDTOOL_SOURCE_ROOT = $(BUILDDIR)/tools/src -BUILDTOOL_MAIN = $(PKGDIR)/FontChecker.java - -# -# Build tool jar rules. -# -include $(BUILDDIR)/common/BuildToolJar.gmk - +-server KNOWN +-client IGNORE +-hotspot ERROR +-classic WARN +-native ERROR +-green ERROR diff --git a/jdk/src/solaris/classes/java/util/prefs/FileSystemPreferences.java b/jdk/src/solaris/classes/java/util/prefs/FileSystemPreferences.java index 0483dba4d1e..ed87311c87a 100644 --- a/jdk/src/solaris/classes/java/util/prefs/FileSystemPreferences.java +++ b/jdk/src/solaris/classes/java/util/prefs/FileSystemPreferences.java @@ -26,12 +26,12 @@ package java.util.prefs; import java.util.*; import java.io.*; -import java.util.logging.Logger; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; +import sun.util.logging.PlatformLogger; /** * Preferences implementation for Unix. Preferences are stored in the file @@ -61,8 +61,8 @@ class FileSystemPreferences extends AbstractPreferences { * Returns logger for error messages. Backing store exceptions are logged at * WARNING level. */ - private static Logger getLogger() { - return Logger.getLogger("java.util.prefs"); + private static PlatformLogger getLogger() { + return PlatformLogger.getLogger("java.util.prefs"); } /** diff --git a/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java b/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java index ed495b177ec..81491abeea3 100644 --- a/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java +++ b/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java @@ -134,7 +134,7 @@ public class X11GraphicsDevice makeConfigurations(); } } - return configs; + return configs.clone(); } private void makeConfigurations() { diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java index 622ff8d4764..fce5560d3de 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java @@ -28,6 +28,7 @@ package sun.nio.ch; import java.io.IOException; import java.util.LinkedList; import java.util.HashSet; +import java.util.Iterator; /** * Manipulates a native array of epoll_event structs on Linux: @@ -200,12 +201,9 @@ class EPollArrayWrapper { void release(SelChImpl channel) { synchronized (updateList) { // flush any pending updates - int i = 0; - while (i < updateList.size()) { - if (updateList.get(i).channel == channel) { - updateList.remove(i); - } else { - i++; + for (Iterator it = updateList.iterator(); it.hasNext();) { + if (it.next().channel == channel) { + it.remove(); } } diff --git a/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java b/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java index 1da339ce9f1..8a0960bc6d8 100644 --- a/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java +++ b/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java @@ -165,7 +165,7 @@ public class Win32GraphicsDevice extends GraphicsDevice implements if (defaultConfig != null) { configs = new GraphicsConfiguration[1]; configs[0] = defaultConfig; - return configs; + return configs.clone(); } } @@ -196,7 +196,7 @@ public class Win32GraphicsDevice extends GraphicsDevice implements configs = new GraphicsConfiguration[v.size()]; v.copyInto(configs); } - return configs; + return configs.clone(); } /** diff --git a/jdk/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java b/jdk/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java index 788a4d0ff21..462223e12d3 100644 --- a/jdk/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java +++ b/jdk/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java @@ -429,7 +429,7 @@ public class D3DGraphicsDevice extends Win32GraphicsDevice { if (defaultConfig != null) { configs = new GraphicsConfiguration[1]; configs[0] = defaultConfig; - return configs; + return configs.clone(); } } } diff --git a/jdk/test/Makefile b/jdk/test/Makefile index da83afb74b1..602d8fc0a91 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1995-2009 Sun Microsystems, Inc. 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,83 +27,141 @@ # Makefile to run various jdk tests # -# Get OS/ARCH specifics -OSNAME = $(shell uname -s) +# Empty these to get rid of some default rules +.SUFFIXES: +.SUFFIXES: .java +CO= +GET= + +# Utilities used +AWK = awk +CAT = cat +CD = cd +CHMOD = chmod +CP = cp +CUT = cut +ECHO = echo +EGREP = egrep +EXPAND = expand +EXPR = expr +KILL = /usr/bin/kill +MKDIR = mkdir +NOHUP = nohup +PWD = pwd +SED = sed +SLEEP = sleep +SORT = sort +TEE = tee +UNAME = uname +UNIQ = uniq +WC = wc +XHOST = xhost +ZIP = zip + +# Get OS name from uname +UNAME_S := $(shell $(UNAME) -s) # Commands to run on paths to make mixed paths for java on windows -GETMIXEDPATH=echo +GETMIXEDPATH=$(ECHO) # Location of developer shared files SLASH_JAVA = /java # Platform specific settings -ifeq ($(OSNAME), SunOS) - PLATFORM = solaris - ARCH = $(shell uname -p) - ifeq ($(ARCH), i386) - ARCH=i586 - endif +ifeq ($(UNAME_S), SunOS) + OS_NAME = solaris + OS_ARCH := $(shell $(UNAME) -p) + OS_VERSION := $(shell $(UNAME) -r) endif -ifeq ($(OSNAME), Linux) - PLATFORM = linux - ARCH = $(shell uname -m) - ifeq ($(ARCH), i386) - ARCH=i586 - endif +ifeq ($(UNAME_S), Linux) + OS_NAME = linux + OS_ARCH := $(shell $(UNAME) -m) + OS_VERSION := $(shell $(UNAME) -r) endif - -# Cannot trust uname output -ifneq ($(PROCESSOR_IDENTIFIER), ) - PLATFORM = windows - SLASH_JAVA = J: - # A variety of ways to say X64 arch :^( - PROC_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) - PROC_ARCH:=$(subst x86,X86,$(PROC_ARCH)) - PROC_ARCH:=$(subst x64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst AMD64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst amd64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst EM64T,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst em64t,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst intel64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst Intel64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst INTEL64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst ia64,IA64,$(PROC_ARCH)) - ifeq ($(PROC_ARCH),IA64) - ARCH = ia64 - else - ifeq ($(PROC_ARCH),X64) - ARCH = x64 +ifndef OS_NAME + ifneq ($(PROCESSOR_IDENTIFIER), ) + OS_NAME = windows + SLASH_JAVA = J: + # A variety of ways to say X64 arch :^( + OS_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) + EXESUFFIX = .exe + # These need to be different depending on MKS or CYGWIN + ifeq ($(findstring cygdrive,$(shell ($(CD) C:/ && $(PWD)))), ) + GETMIXEDPATH = dosname -s + OS_VERSION := $(shell $(UNAME) -r) else - ARCH = i586 + GETMIXEDPATH = cygpath -m -s + OS_VERSION := $(shell $(UNAME) -s | $(CUT) -d'-' -f2) endif endif - EXESUFFIX = .exe - # These need to be different depending on MKS or CYGWIN - ifeq ($(findstring cygdrive,$(shell (cd C:/ && pwd))), ) - GETMIXEDPATH=dosname -s +endif + +# Only want major and minor numbers from os version +OS_VERSION := $(shell $(ECHO) "$(OS_VERSION)" | $(CUT) -d'.' -f1,2) + +# Try and use names i586, x64, and ia64 consistently +OS_ARCH:=$(subst X64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst AMD64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst amd64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst x86_64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst EM64T,x64,$(OS_ARCH)) +OS_ARCH:=$(subst em64t,x64,$(OS_ARCH)) +OS_ARCH:=$(subst intel64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst Intel64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst INTEL64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst IA64,ia64,$(OS_ARCH)) +OS_ARCH:=$(subst X86,i586,$(OS_ARCH)) +OS_ARCH:=$(subst x86,i586,$(OS_ARCH)) +OS_ARCH:=$(subst i386,i586,$(OS_ARCH)) +OS_ARCH:=$(subst i486,i586,$(OS_ARCH)) +OS_ARCH:=$(subst i686,i586,$(OS_ARCH)) + +# Check for ARCH_DATA_MODEL, adjust OS_ARCH accordingly +ifndef ARCH_DATA_MODEL + ARCH_DATA_MODEL=32 +endif +ARCH_DATA_MODEL_ERROR= \ + ARCH_DATA_MODEL=$(ARCH_DATA_MODEL) cannot be used with $(OS_NAME)-$(ARCH) +ifeq ($(ARCH_DATA_MODEL),64) + ifeq ($(OS_NAME)-$(OS_ARCH),solaris-i586) + OS_ARCH=x64 + endif + ifeq ($(OS_NAME)-$(OS_ARCH),solaris-sparc) + OS_ARCH=sparcv9 + endif + ifeq ($(OS_ARCH),i586) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif + ifeq ($(OS_ARCH),sparc) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif +else + ifeq ($(ARCH_DATA_MODEL),32) + ifeq ($(OS_ARCH),x64) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif + ifeq ($(OS_ARCH),ia64) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif + ifeq ($(OS_ARCH),sparcv9) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif else - GETMIXEDPATH=cygpath -m -s + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") endif endif -# Utilities used -CD = cd -CP = cp -ECHO = echo -MKDIR = mkdir -ZIP = zip - # Root of this test area (important to use full paths in some places) -TEST_ROOT := $(shell pwd) +TEST_ROOT := $(shell $(PWD)) # Root of all test results ifdef ALT_OUTPUTDIR ABS_OUTPUTDIR = $(ALT_OUTPUTDIR) else - ABS_OUTPUTDIR = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) + ABS_OUTPUTDIR = $(TEST_ROOT)/../build/$(OS_NAME)-$(OS_ARCH) endif ABS_BUILD_ROOT = $(ABS_OUTPUTDIR) -ABS_TEST_OUTPUT_DIR := $(ABS_BUILD_ROOT)/testoutput +ABS_TEST_OUTPUT_DIR := $(ABS_BUILD_ROOT)/testoutput/$(UNIQUE_DIR) # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test) ifndef PRODUCT_HOME @@ -114,13 +172,14 @@ ifndef PRODUCT_HOME if [ -d $(ABS_JDK_IMAGE) ] ; then \ $(ECHO) "$(ABS_JDK_IMAGE)"; \ else \ - $(ECHO) "$(ABS_BUILD_ROOT)" ; \ + $(ECHO) "$(ABS_BUILD_ROOT)"; \ fi) PRODUCT_HOME := $(PRODUCT_HOME) endif # Expect JPRT to set JPRT_PRODUCT_ARGS (e.g. -server etc.) # Should be passed into 'java' only. +# Could include: -d64 -server -client OR any java option ifdef JPRT_PRODUCT_ARGS JAVA_ARGS = $(JPRT_PRODUCT_ARGS) endif @@ -131,18 +190,131 @@ ifdef JPRT_PRODUCT_VM_ARGS JAVA_VM_ARGS = $(JPRT_PRODUCT_VM_ARGS) endif +# Check JAVA_ARGS arguments based on ARCH_DATA_MODEL etc. +ifeq ($(OS_NAME),solaris) + D64_ERROR_MESSAGE=Mismatch between ARCH_DATA_MODEL=$(ARCH_DATA_MODEL) and use of -d64 in JAVA_ARGS=$(JAVA_ARGS) + ifeq ($(ARCH_DATA_MODEL),32) + ifneq ($(findstring -d64,$(JAVA_ARGS)),) + x:=$(warning "WARNING: $(D64_ERROR_MESSAGE)") + endif + endif + ifeq ($(ARCH_DATA_MODEL),64) + ifeq ($(findstring -d64,$(JAVA_ARGS)),) + x:=$(warning "WARNING: $(D64_ERROR_MESSAGE)") + endif + endif +endif + # Expect JPRT to set JPRT_ARCHIVE_BUNDLE (path to zip bundle for results) ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip ifdef JPRT_ARCHIVE_BUNDLE ARCHIVE_BUNDLE = $(JPRT_ARCHIVE_BUNDLE) endif +# DISPLAY settings for virtual frame buffer +START_XVFB = start-Xvfb.sh +NOHUP_OUTPUT = $(ABS_TEST_OUTPUT_DIR)/start-Xvfb.nohup-output.txt +DISPLAY_PID_FILE=$(ABS_TEST_OUTPUT_DIR)/xvfb-display-number.txt +DISPLAY_SLEEP_TIME=10 +DISPLAY_MAX_SLEEPS=10 +ifeq ($(OS_NAME),solaris) + VIRTUAL_FRAME_BUFFER = true +endif +ifeq ($(OS_NAME),linux) + VIRTUAL_FRAME_BUFFER = true +endif + +# Does not work yet, display dies as soon as it gets used. :^( +VIRTUAL_FRAME_BUFFER = false + +# Are we using a VIRTUAL_FRAME_BUFFER (Xvfb) +ifeq ($(VIRTUAL_FRAME_BUFFER),true) + + PREP_DISPLAY = \ + $(CP) $(START_XVFB) $(ABS_TEST_OUTPUT_DIR); \ + $(CHMOD) a+x $(ABS_TEST_OUTPUT_DIR)/$(START_XVFB); \ + ( $(CD) $(ABS_TEST_OUTPUT_DIR) && \ + $(NOHUP) $(ABS_TEST_OUTPUT_DIR)/$(START_XVFB) $(DISPLAY_PID_FILE) > $(NOHUP_OUTPUT) 2>&1 && \ + $(SLEEP) $(DISPLAY_SLEEP_TIME) ) & \ + count=1; \ + while [ ! -s $(DISPLAY_PID_FILE) ] ; do \ + $(ECHO) "Sleeping $(DISPLAY_SLEEP_TIME) more seconds, DISPLAY not ready"; \ + $(SLEEP) $(DISPLAY_SLEEP_TIME); \ + count=`$(EXPR) $${count} '+' 1`; \ + if [ $${count} -gt $(DISPLAY_MAX_SLEEPS) ] ; then \ + $(ECHO) "ERROR: DISPLAY not ready, giving up on DISPLAY"; \ + exit 9; \ + fi; \ + done ; \ + DISPLAY=":`$(CAT) $(DISPLAY_PID_FILE)`"; \ + export DISPLAY; \ + $(CAT) $(NOHUP_OUTPUT); \ + $(ECHO) "Prepared DISPLAY=$${DISPLAY}"; \ + $(XHOST) || \ + ( $(ECHO) "ERROR: No display" ; exit 8) + + KILL_DISPLAY = \ + ( \ + DISPLAY=":`$(CAT) $(DISPLAY_PID_FILE)`"; \ + export DISPLAY; \ + if [ -s "$(DISPLAY_PID_FILE)" ] ; then \ + $(KILL) `$(CAT) $(DISPLAY_PID_FILE)` > /dev/null 2>&1; \ + $(KILL) -9 `$(CAT) $(DISPLAY_PID_FILE)` > /dev/null 2>&1; \ + fi; \ + $(ECHO) "Killed DISPLAY=$${DISPLAY}"; \ + ) + +else + + PREP_DISPLAY = $(ECHO) "VIRTUAL_FRAME_BUFFER=$(VIRTUAL_FRAME_BUFFER)" + KILL_DISPLAY = $(ECHO) "VIRTUAL_FRAME_BUFFER=$(VIRTUAL_FRAME_BUFFER)" + +endif + # How to create the test bundle (pass or fail, we want to create this) # Follow command with ";$(BUNDLE_UP_AND_EXIT)", so it always gets executed. ZIP_UP_RESULTS = ( $(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)` \ && $(CD) $(ABS_TEST_OUTPUT_DIR) \ && $(ZIP) -q -r $(ARCHIVE_BUNDLE) . ) -BUNDLE_UP_AND_EXIT = ( exitCode=$$? && $(ZIP_UP_RESULTS) && exit $${exitCode} ) +SUMMARY_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport/text/summary.txt +STATS_TXT_NAME = Stats.txt +STATS_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/$(STATS_TXT_NAME) +RUNLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/runlist.txt +PASSLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/passlist.txt +FAILLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/faillist.txt +BUNDLE_UP_AND_EXIT = \ +( \ + exitCode=$$? && \ + _summary="$(SUMMARY_TXT)"; \ + $(RM) -f $(STATS_TXT) $(RUNLIST) $(PASSLIST) $(FAILLIST); \ + if [ -r "$${_summary}" ] ; then \ + $(ECHO) "Summary: $${_summary}" > $(STATS_TXT); \ + $(EXPAND) $${_summary} | $(EGREP) -v ' Not run\.' > $(RUNLIST); \ + $(EGREP) ' Passed\.' $(RUNLIST) \ + | $(EGREP) -v ' Error\.' \ + | $(EGREP) -v ' Failed\.' > $(PASSLIST); \ + ( $(EGREP) ' Failed\.' $(RUNLIST); \ + $(EGREP) ' Error\.' $(RUNLIST); \ + $(EGREP) -v ' Passed\.' $(RUNLIST) ) \ + | $(SORT) | $(UNIQ) > $(FAILLIST); \ + if [ $${exitCode} != 0 -o -s $(FAILLIST) ] ; then \ + $(EXPAND) $(FAILLIST) \ + | $(CUT) -d' ' -f1 \ + | $(SED) -e 's@^@FAILED: @' >> $(STATS_TXT); \ + fi; \ + runc="`$(CAT) $(RUNLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ + passc="`$(CAT) $(PASSLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ + failc="`$(CAT) $(FAILLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ + exclc="`$(CAT) $(EXCLUDELIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ + $(ECHO) "TEST STATS: run=$${runc} pass=$${passc} fail=$${failc} excluded=$${exclc}" \ + >> $(STATS_TXT); \ + else \ + $(ECHO) "Missing file: $${_summary}" >> $(STATS_TXT); \ + fi; \ + $(CAT) $(STATS_TXT); \ + $(ZIP_UP_RESULTS) && $(KILL_DISPLAY) && \ + exit $${exitCode} \ +) ################################################################ @@ -172,32 +344,239 @@ endif # Expect JPRT to set TESTDIRS to the jtreg test dirs ifndef TESTDIRS - TESTDIRS = demo/jvmti/gctest demo/jvmti/hprof + TESTDIRS = demo endif +# Samevm settings (default is false) +ifndef USE_JTREG_SAMEVM + USE_JTREG_SAMEVM=false +endif +# With samevm, you cannot use -javaoptions? +ifeq ($(USE_JTREG_SAMEVM),true) + EXTRA_JTREG_OPTIONS += -samevm $(JAVA_ARGS) $(JAVA_ARGS:%=-vmoption:%) + JTREG_TEST_OPTIONS = $(JAVA_VM_ARGS:%=-vmoption:%) +else + JTREG_TEST_OPTIONS = $(JAVA_ARGS:%=-javaoptions:%) $(JAVA_VM_ARGS:%=-vmoption:%) +endif + +# Some tests annoy me and fail frequently +PROBLEM_LIST=ProblemList.txt +EXCLUDELIST=$(ABS_TEST_OUTPUT_DIR)/excludelist.txt + +# Create exclude list for this platform and arch +ifdef NO_EXCLUDES +$(EXCLUDELIST): $(PROBLEM_LIST) $(TESTDIRS) + @$(ECHO) "NOTHING_EXCLUDED" > $@ +else +$(EXCLUDELIST): $(PROBLEM_LIST) $(TESTDIRS) + @$(RM) $@ $@.temp1 $@.temp2 + @( ( $(EGREP) -- '$(OS_NAME)-all' $< ) ;\ + ( $(EGREP) -- '$(OS_NAME)-$(OS_ARCH)' $< ) ;\ + ( $(EGREP) -- '$(OS_NAME)-$(OS_VERSION)' $< ) ;\ + ( $(EGREP) -- 'generic-$(OS_ARCH)' $< ) ;\ + ( $(EGREP) -- 'generic-all' $< ) ;\ + ( $(ECHO) "#") ;\ + ) | $(SED) -e 's@^[\ ]*@@' \ + | $(EGREP) -v '^#' > $@.temp1 + @for tdir in $(TESTDIRS) ; do \ + ( ( $(CAT) $@.temp1 | $(EGREP) "^$${tdir}" ) ; $(ECHO) "#" ) >> $@.temp2 ; \ + done + @$(ECHO) "# at least one line" >> $@.temp2 + @( $(EGREP) -v '^#' $@.temp2 ; true ) > $@ + @$(ECHO) "Excluding list contains `$(EXPAND) $@ | $(WC) -l` items" +endif + +# Running batches of tests with or without samevm +define RunSamevmBatch +$(ECHO) "Running tests in samevm mode: $?" +$(MAKE) TESTDIRS="$?" USE_JTREG_SAMEVM=true UNIQUE_DIR=$@ jtreg_tests +endef +define RunOthervmBatch +$(ECHO) "Running tests in othervm mode: $?" +$(MAKE) TESTDIRS="$?" USE_JTREG_SAMEVM=false UNIQUE_DIR=$@ jtreg_tests +endef +define SummaryInfo +$(ECHO) "Summary for: $?" +$(CAT) $(?:%=$(ABS_TEST_OUTPUT_DIR)/%/$(STATS_TXT_NAME)) +endef + +# ------------------------------------------------------------------ + +# Batches of tests (somewhat arbitrary assigments to jdk_* targets) +JDK_ALL_TARGETS = + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has problems, and doesn't help performance as much as others. +JDK_ALL_TARGETS += jdk_awt +jdk_awt: com/sun/awt java/awt sun/awt + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_beans1 +jdk_beans1: java/beans/beancontext java/beans/PropertyChangeSupport \ + java/beans/Introspector java/beans/Performance \ + java/beans/VetoableChangeSupport java/beans/Statement + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_beans2 +jdk_beans2: java/beans/Beans java/beans/EventHandler java/beans/XMLDecoder \ + java/beans/PropertyEditor + $(call RunOthervmBatch) +JDK_ALL_TARGETS += jdk_beans3 +jdk_beans3: java/beans/XMLEncoder + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_io +jdk_io: java/io + $(call RunSamevmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_lang +jdk_lang: java/lang + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_management1 +jdk_management1: javax/management + $(call RunOthervmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_management2 +jdk_management2: com/sun/jmx com/sun/management sun/management + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_math +jdk_math: java/math + $(call RunSamevmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_misc +jdk_misc: demo javax/imageio javax/naming javax/print javax/script \ + javax/smartcardio javax/sound com/sun/java com/sun/jndi \ + com/sun/org sun/misc sun/pisces + $(call RunSamevmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_net +jdk_net: com/sun/net java/net sun/net + $(call RunSamevmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_nio1 +jdk_nio1: java/nio/file + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_nio2 +jdk_nio2: java/nio/Buffer java/nio/ByteOrder \ + java/nio/channels java/nio/BufferPoolMXBean java/nio/MappedByteBuffer + $(call RunOthervmBatch) +JDK_ALL_TARGETS += jdk_nio3 +jdk_nio3: com/sun/nio sun/nio + $(call RunOthervmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_rmi +jdk_rmi: java/rmi javax/rmi sun/rmi + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_security1 +jdk_security1: java/security + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_security2 +jdk_security2: javax/crypto com/sun/crypto + $(call RunOthervmBatch) +JDK_ALL_TARGETS += jdk_security3 +jdk_security3: com/sun/security lib/security javax/security sun/security + $(call RunOthervmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has problems, and doesn't help performance as much as others. +JDK_ALL_TARGETS += jdk_swing +jdk_swing: javax/swing sun/java2d + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_text +jdk_text: java/text sun/text + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_tools1 +jdk_tools1: com/sun/jdi + $(call RunOthervmBatch) +JDK_ALL_TARGETS += jdk_tools2 +jdk_tools2: com/sun/tools sun/jvmstat sun/tools tools vm com/sun/servicetag com/sun/tracing + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_util +jdk_util: java/util sun/util + $(call RunSamevmBatch) + +# ------------------------------------------------------------------ + +# Run all tests +jdk_all: $(filter-out jdk_awt jdk_rmi jdk_swing, $(JDK_ALL_TARGETS)) + @$(SummaryInfo) + +# These are all phony targets +PHONY_LIST += $(JDK_ALL_TARGETS) + +# ------------------------------------------------------------------ + # Default JTREG to run (win32 script works for everybody) JTREG = $(JT_HOME)/win32/bin/jtreg +# Add any extra options (samevm etc.) +JTREG_BASIC_OPTIONS += $(EXTRA_JTREG_OPTIONS) +# Only run automatic tests +JTREG_BASIC_OPTIONS += -a +# Report details on all failed or error tests, times too +JTREG_BASIC_OPTIONS += -v:fail,error,time +# Retain all files for failing tests +JTREG_BASIC_OPTIONS += -retain:fail,error +# Ignore tests are not run and completely silent about it +JTREG_BASIC_OPTIONS += -ignore:quiet +# Multiple by 2 the timeout numbers +JTREG_BASIC_OPTIONS += -timeoutFactor:2 +# Boost the max memory for jtreg to avoid gc thrashing +JTREG_BASIC_OPTIONS += -J-Xmx512m -jtreg_tests: prep $(JT_HOME) $(PRODUCT_HOME) $(JTREG) - $(RM) $(JTREG).orig - cp $(JTREG) $(JTREG).orig - $(RM) $(JTREG) - sed -e 's@-J\*@-J-*@' $(JTREG).orig > $(JTREG) - chmod a+x $(JTREG) - ( JT_HOME=$(shell $(GETMIXEDPATH) "$(JT_HOME)"); \ - export JT_HOME; \ - $(shell $(GETMIXEDPATH) "$(JTREG)") \ - -a -v:fail,error \ - -ignore:quiet \ - -timeoutFactor:2 \ - $(EXTRA_JTREG_OPTIONS) \ - -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport \ - -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTwork \ - -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \ - $(JAVA_ARGS:%=-javaoptions:%) \ - $(JAVA_VM_ARGS:%=-vmoption:%) \ - $(TESTDIRS) \ - ) ; $(BUNDLE_UP_AND_EXIT) +# Make sure jtreg exists +$(JTREG): $(JT_HOME) + +# Run jtreg +jtreg_tests: prep $(PRODUCT_HOME) $(JTREG) $(EXCLUDELIST) + @$(EXPAND) $(EXCLUDELIST) \ + | $(CUT) -d' ' -f1 \ + | $(SED) -e 's@^@Excluding: @' + ( \ + ( JT_HOME=$(shell $(GETMIXEDPATH) "$(JT_HOME)"); \ + export JT_HOME; \ + $(PREP_DISPLAY) && \ + $(shell $(GETMIXEDPATH) "$(JTREG)") \ + $(JTREG_BASIC_OPTIONS) \ + -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport \ + -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTwork \ + -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \ + -exclude:$(shell $(GETMIXEDPATH) "$(EXCLUDELIST)") \ + $(JTREG_TEST_OPTIONS) \ + $(TESTDIRS) \ + ) ; $(BUNDLE_UP_AND_EXIT) \ + ) 2>&1 | $(TEE) $(ABS_TEST_OUTPUT_DIR)/output.txt PHONY_LIST += jtreg_tests diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt new file mode 100644 index 00000000000..9a366c1ba8f --- /dev/null +++ b/jdk/test/ProblemList.txt @@ -0,0 +1,1211 @@ +########################################################################### +# +# Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# +########################################################################### +# +# List of tests that should not be run by test/Makefile, for various reasons: +# 1. Does not run with jtreg -samevm mode +# 2. Causes problems in jtreg -samevm mode for jtreg or tests that follow it +# 3. The test is too slow or consumes too many system resources +# 4. The test fails when run on any official build systems +# +# It is possible that a test being on this list is a mistake, and that some +# other test in samevm mode caused tests to fail, mistakes happen. +# +# Tests marked @ignore are not run by test/Makefile, but harmless to be listed. +# +# Tests that explicitly state "@run main/othervm ...", and are not listed here, +# will be run in the same batch as the samevm tests. +# +# Shell tests are othervm by default. +# +# List items are testnames followed by labels, all MUST BE commented +# as to why they are here and use a label: +# generic-all Problems on all platforms +# generic-ARCH Where ARCH is one of: sparc, sparcv9, x64, i586, etc. +# OSNAME-all Where OSNAME is one of: solaris, linux, windows +# OSNAME-ARCH Specific on to one OSNAME and ARCH, e.g. solaris-x64 +# OSNAME-REV Specific on to one OSNAME and REV, e.g. solaris-5.8 +# +# More than one label is allowed but must be on the same line. +# +############################################################################# +# +# Running the tests: +# cd test && make JT_HOME=jtreg_home PRODUCT_HOME=jdk_home jdk_all +# Or instead of jdk_all, use any of the jdk_* targets. +# +# Samevm Notes: +# * Although some tests may have only been seen to fail on some platforms, +# they might be flagged as 'generic-all' because the problem they have +# could cause hidden slowdowns on other platforms. +# Most samevm problems will be generic-all, but windows usually dislikes +# them the most. +# Address already in use or connection errors indicate a generic port issue. +# (this is not necessarily a samevm issue, but an issue for running the tests +# on shared machines, two people or two test runs will collide). +# * Samevm problem (windows in particular) is not closing all input/output +# * Samevm problem when a test calls setSecurityManager() +# * Samevm problem with setHttps*() is used? (not exactly sure here) +# * Samevm problem when stuffing system properties with non Strings or anything +# * Samevm problem when changing vm settings, or registering any vm actions +# * Samevm problems with deleteOnExit(), if it must happen at end of test +# * Samevm problems with URLClassLoader? (no details here) +# * Samevm problems with dependence on predictable GC or finalizations +# +# Any of the above problems may mean the test needs to be flagged as "othervm". +# +############################################################################# +# +# Fixing the tests: +# +# Some tests just may need to be run with "othervm", and that can easily be +# done my adding a @run line (or modifying any existing @run): +# @run main/othervm NameOfMainClass +# Make sure this @run follows any use of @library. +# Otherwise, if the test is a samevm possibility, make sure the test is +# cleaning up after itself, closing all streams, deleting temp files, etc. +# +# Keep in mind that the bug could be in many places, and even different per +# platform, it could be a bug in any one of: +# - the testcase +# - the jdk (jdk classes, native code, or hotspot) +# - the native compiler +# - the javac compiler +# - the OS (depends on what the testcase does) +# +# If you managed to really fix one of these tests, here is how you can +# remove tests from this list: +# 1. Make sure test passes on all platforms with samevm, or mark it othervm +# 2. Make sure test passes on all platforms when run with it's entire group +# 3. Make sure both VMs are tested, -server and -client, if possible +# 4. Make sure you try the -d64 option on Solaris +# 5. Use a tool like JPRT or something to verify these results +# 6. Delete lines in this file, include the changes with your test changes +# +# You may need to repeat your testing 2 or even 3 times to verify good +# results, some of these samevm failures are not very predictable. +# +############################################################################# + +############################################################################ + +# jdk_awt + +# None of the awt tests are using samevm, might not be worth the effort due +# to the vm overhead not being enough to make a difference. +# In general, the awt tests are problematic with or without samevm, and there +# are issues with using a Xvfb display. + +# Fails on solaris sparc, timedout? in othervm mode +java/awt/event/MouseEvent/AcceptExtraButton/AcceptExtraButton.java generic-all + +# Causes hang in samevm mode??? Solaris 11 i586 +java/awt/FullScreen/SetFSWindow/FSFrame.java generic-all + +# Fails on solaris 11 i586, -client, in othervm mode not sure why +java/awt/Component/PrintAllXcheckJNI/PrintAllXcheckJNI.java generic-all +java/awt/Focus/CloseDialogActivateOwnerTest/CloseDialogActivateOwnerTest.java generic-all +java/awt/FontClass/FontAccess.java generic-all +java/awt/Mixing/HWDisappear.java generic-all +java/awt/Mixing/MixingInHwPanel.java generic-all +java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html generic-all +java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java generic-all +java/awt/Toolkit/SecurityTest/SecurityTest2.java generic-all +java/awt/image/mlib/MlibOpsTest.java generic-all + +# Fails on windows, othervm mode, various errors +java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java generic-all +java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java generic-all +java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java generic-all +java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java generic-all +java/awt/event/KeyEvent/KeyTyped/CtrlASCII.html generic-all +java/awt/font/Threads/FontThread.java generic-all +java/awt/print/PrinterJob/PrtException.java generic-all + +# Fails with windows X64, othervm, -server +com/sun/awt/Translucency/WindowOpacity.java generic-all +java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java generic-all +java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.html generic-all +java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest1.html generic-all +java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java generic-all +java/awt/Frame/LayoutOnMaximizeTest/LayoutOnMaximizeTest.java generic-all +java/awt/FullScreen/TranslucentWindow/TranslucentWindow.java generic-all +java/awt/Mixing/MixingOnShrinkingHWButton.java generic-all +java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java generic-all + +############################################################################ + +# jdk_beans + +# A large set of the beans tests set the security manager, which would seem +# to indicate that a large number of them should be "othervm", yet are all +# very small tests and could greatly benefit from a samevm test run. +# So a large batch of beans tests are currently run with othervm mode. + +# Linux, some kind of problems with X11 display +java/beans/PropertyChangeSupport/Test4682386.java generic-all +java/beans/PropertyChangeSupport/TestSynchronization.java generic-all +java/beans/Statement/Test4653179.java generic-all + +# Runs REALLY slow on Solaris sparc for some reason, both -client and -server +java/beans/XMLEncoder/Test4625418.java solaris-sparc + +# Problems with samevm and setting security manager (speculation partially) +java/beans/Beans/Test4080522.java generic-all +java/beans/EventHandler/Test6277246.java generic-all +java/beans/EventHandler/Test6277266.java generic-all +java/beans/Introspector/Test6277246.java generic-all +java/beans/Introspector/4168475/Test4168475.java generic-all +java/beans/Introspector/4520754/Test4520754.java generic-all +java/beans/Introspector/6380849/TestBeanInfo.java generic-all +java/beans/Introspector/Test4144543.java generic-all + +# Failed to call method solaris-sparc??? +java/beans/EventHandler/Test6788531.java generic-all + +# Jar or class not found??? +java/beans/XMLEncoder/6329581/Test6329581.java generic-all + +############################################################################ + +# jdk_io + +# Many of these tests have a tendency to leave input streams open, which +# will cause following tests to be failures when used in samevm mode. + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/BufferedReader/BigMark.java generic-all +java/io/BufferedReader/ReadLineSync.java generic-all + +# One of these is leaving "a.ser" file open, windows samevm +java/io/Serializable/duplicateSerialFields/Setup.java generic-all +java/io/Serializable/duplicateSerialFields/Test.java generic-all + +# One of these leaving foo.ser open, windows samevm problem +java/io/Serializable/enum/constantSubclasses/Read.java generic-all +java/io/Serializable/enum/constantSubclasses/Write.java generic-all +java/io/Serializable/enum/missingConstant/Read.java generic-all +java/io/Serializable/enum/missingConstant/Write.java generic-all + +# This is leaving subtest1.tmp open, windows samevm problem +java/io/Serializable/oldTests/AnnotateClass.java generic-all + +# One or more of these leave a piotest* file open, windows samevm +java/io/Serializable/oldTests/ArrayFields.java generic-all +java/io/Serializable/oldTests/ArraysOfArrays.java generic-all +java/io/Serializable/oldTests/BinaryTree.java generic-all +java/io/Serializable/oldTests/CircularList.java generic-all +java/io/Serializable/oldTests/SerializeWithException.java generic-all +java/io/Serializable/oldTests/SimpleArrays.java generic-all +java/io/Serializable/oldTests/WritePrimitive.java generic-all + +# Missing close on file 0.ser, windows samevm +java/io/Serializable/enum/badResolve/Read.java generic-all +java/io/Serializable/enum/badResolve/Write.java generic-all + +# One of these tests is leaving parents.ser open, windows samevm +java/io/Serializable/parents/EvolvedClass.java generic-all +java/io/Serializable/parents/OriginalClass.java generic-all + +# One of these tests is leaving file foo.ser and/or bar.ser open, windows samevm +java/io/Serializable/fieldTypeString/Read.java generic-all +java/io/Serializable/fieldTypeString/Write.java generic-all + +# One of these tests is leaving tmp.ser file open, windows samevm +java/io/Serializable/ClassCastExceptionDetail/Read.java generic-all +java/io/Serializable/ClassCastExceptionDetail/Write.java generic-all +java/io/Serializable/GetField/Read.java generic-all +java/io/Serializable/GetField/Read2.java generic-all +java/io/Serializable/GetField/Write.java generic-all +java/io/Serializable/PutField/Read.java generic-all +java/io/Serializable/PutField/Read2.java generic-all +java/io/Serializable/PutField/Write.java generic-all +java/io/Serializable/PutField/Write2.java generic-all +java/io/Serializable/arraySuidConflict/Read.java generic-all +java/io/Serializable/arraySuidConflict/Write.java generic-all +java/io/Serializable/backRefCNFException/Read.java generic-all +java/io/Serializable/backRefCNFException/Write.java generic-all +java/io/Serializable/class/Test.java generic-all +java/io/Serializable/evolution/AddedExternField/ReadAddedField.java generic-all +java/io/Serializable/evolution/AddedExternField/WriteAddedField.java generic-all +java/io/Serializable/evolution/AddedExternField/run.sh generic-all +java/io/Serializable/evolution/AddedField/ReadAddedField.java generic-all +java/io/Serializable/evolution/AddedField/WriteAddedField.java generic-all +java/io/Serializable/evolution/AddedSuperClass/ReadAddedSuperClass.java generic-all +java/io/Serializable/evolution/AddedSuperClass/ReadAddedSuperClass2.java generic-all +java/io/Serializable/evolution/AddedSuperClass/WriteAddedSuperClass.java generic-all +java/io/Serializable/proxy/skipMissing/Read.java generic-all +java/io/Serializable/proxy/skipMissing/Write.java generic-all +java/io/Serializable/readObjectNoData/Read.java generic-all +java/io/Serializable/readObjectNoData/Write.java generic-all +java/io/Serializable/skipWriteObject/Read.java generic-all +java/io/Serializable/skipWriteObject/Write.java generic-all +java/io/Serializable/skippedObjCNFException/Read.java generic-all +java/io/Serializable/skippedObjCNFException/Write.java generic-all +java/io/Serializable/stopCustomDeserialization/Read.java generic-all +java/io/Serializable/stopCustomDeserialization/Write.java generic-all +java/io/Serializable/unresolvedClassDesc/Read.java generic-all +java/io/Serializable/unresolvedClassDesc/Write.java generic-all +java/io/Serializable/unshared/Read.java generic-all +java/io/Serializable/unshared/Write.java generic-all +java/io/Serializable/wrongReturnTypes/Read.java generic-all +java/io/Serializable/wrongReturnTypes/Write.java generic-all + +# Windows samevm issues? triggers other tests to fail, missing close() on f.txt? +java/io/DataInputStream/OpsAfterClose.java generic-all + +# Windows 32bit samevm failure: RuntimeException: File.getFreeSpace() failed +java/io/File/MaxPathLength.java generic-all + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/File/DeleteOnExit.java generic-all +java/io/File/DeleteOnExitLong.java generic-all +java/io/File/DeleteOnExitNPE.java generic-all +java/io/File/IsHidden.java generic-all +java/io/FileDescriptor/FileChannelFDTest.java generic-all +java/io/FileDescriptor/Finalize.java generic-all +java/io/FileInputStream/FinalizeShdCallClose.java generic-all + +# Known to cause samevm issues on windows, other tests fail, missing close()? +java/io/FileInputStream/OpsAfterClose.java generic-all + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/FileOutputStream/FinalizeShdCallClose.java generic-all + +# Known to cause samevm issues on windows, other tests fail, missing close()? +java/io/FileOutputStream/OpsAfterClose.java generic-all + +# Windows samevm issues? triggers other tests to fail, missing close() on f.txt? +java/io/InputStream/OpsAfterClose.java generic-all + +# Missing close() on x.ReadBounds file? Windows samevm issues +java/io/InputStream/ReadParams.java generic-all + +# Known to cause samevm issues on windows, other tests fail, missing close()? +java/io/InputStreamReader/GrowAfterEOF.java generic-all + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/ObjectInputStream/ResolveProxyClass.java generic-all + +# Not doing a close() on x.ParameterCheck file? windows samevm cascade error +java/io/RandomAccessFile/ParameterCheck.java generic-all + +# Not doing a close on x.ReadLine file? windows cascade samevm problems +java/io/RandomAccessFile/ReadLine.java generic-all + +# Not doing close on file input x.WriteByteChars, windows samevm problems +java/io/RandomAccessFile/WriteBytesChars.java generic-all + +# Not doing close on file input x.WriteUTF, windows samevm problems +java/io/RandomAccessFile/WriteUTF.java generic-all + +# Possibly, not doing a close() on input.txt, windows samevm issues. +java/io/RandomAccessFile/skipBytes/SkipBytes.java generic-all +java/io/readBytes/MemoryLeak.java generic-all +java/io/readBytes/ReadBytesBounds.java generic-all + +# Missing close on fields.ser, windows samevm +java/io/Serializable/checkModifiers/CheckModifiers.java generic-all + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/Serializable/auditStreamSubclass/AuditStreamSubclass.java generic-all +java/io/Serializable/proxy/Basic.java generic-all + +# Possibly not doing a close() on input.txt, windows samevm issues. +java/io/StreamTokenizer/Comment.java generic-all + +############################################################################ + +# jdk_lang + +# Some of these tests (like java/lang/management) may just need to be marked +# othervm, but that is partially speculation. + +# Times out on solaris 10 sparc +java/lang/ClassLoader/Assert.java generic-all + +# Fedora 9 X64, RuntimeException: MyThread expected to be blocked on lock, but got null +java/lang/management/ThreadMXBean/ThreadStateTest.java generic-all + +# RuntimeException: Uptime of the JVM is more than 30 minutes (32 minutes). +java/lang/management/RuntimeMXBean/UpTime.java generic-all + +# Times out on solaris sparc occasionally, in samevm mode +java/lang/Runtime/exec/ExecWithDir.java generic-all +java/lang/ProcessBuilder/Basic.java generic-all + +# Solaris sparc, samevm, java.lang.Exception: Read from closed pipe hangs +java/lang/Runtime/exec/SleepyCat.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/annotation/ParameterAnnotations.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/ClassLoader/defineClass/DefineClassByteBuffer.java generic-all +java/lang/ClassLoader/findSystemClass/Loader.java generic-all + +# Fedora 9 32bit, -client, samevm, Error while cleaning up threads after test +java/lang/management/ThreadMXBean/Locks.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/management/ClassLoadingMXBean/LoadCounts.java generic-all +java/lang/management/ManagementFactory/MBeanServerMXBeanUnsupportedTest.java generic-all +java/lang/management/ManagementFactory/MXBeanProxyTest.java generic-all +java/lang/management/ManagementFactory/ThreadMXBeanProxy.java generic-all +java/lang/management/MemoryMXBean/CollectionUsageThreshold.java generic-all +java/lang/management/MemoryMXBean/GetMBeanInfo.java generic-all +java/lang/management/MemoryMXBean/LowMemoryTest.java generic-all +java/lang/management/MemoryMXBean/MemoryManagement.java generic-all +java/lang/management/MemoryMXBean/MemoryTest.java generic-all +java/lang/management/MemoryMXBean/Pending.java generic-all + +# Problematic on all platforms (even as othervm) +java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java generic-all + +# Causes jtreg exit samevm issues due to non-String object in system properties +java/lang/management/RuntimeMXBean/GetSystemProperties.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/management/RuntimeMXBean/PropertiesTest.java generic-all +java/lang/management/ThreadMXBean/AllThreadIds.java generic-all +java/lang/management/ThreadMXBean/EnableTest.java generic-all +java/lang/management/ThreadMXBean/FindMonitorDeadlock.java generic-all +java/lang/management/ThreadMXBean/LockingThread.java generic-all +java/lang/management/ThreadMXBean/MonitorDeadlock.java generic-all +java/lang/management/ThreadMXBean/MyOwnSynchronizer.java generic-all +java/lang/management/ThreadMXBean/SharedSynchronizer.java generic-all +java/lang/management/ThreadMXBean/SynchronizerLockingThread.java generic-all +java/lang/management/ThreadMXBean/ThreadCounts.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/reflect/Proxy/Boxing.java generic-all +java/lang/reflect/Proxy/ClassRestrictions.java generic-all +java/lang/reflect/Proxy/returnTypes/Test.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/Runtime/exec/LotsOfOutput.java generic-all +java/lang/System/ExitFinalizersAndJIT.java generic-all +java/lang/System/finalization/FinThreads.java generic-all +java/lang/System/IgnoreNullSecurityManager.java generic-all +java/lang/Thread/GenerifyStackTraces.java generic-all +java/lang/Thread/StackTraces.java generic-all +java/lang/ThreadGroup/Daemon.java generic-all +java/lang/ThreadGroup/NullThreadName.java generic-all + +# Times out on solaris sparc -server +java/lang/ThreadLocal/MemoryLeak.java solaris-all + +# Windows X64, RuntimeException: MyThread expected to have RUNNABLE but got WAITING +java/lang/Thread/ThreadStateTest.java generic-all + +# Timeout on windows 64bit +java/lang/ClassLoader/deadlock/TestCrossDelegate.sh generic-all + +############################################################################ + +# jdk_management + +# Solaris 10 sparc, NPE from org.omg.stub.javax.management.remote.rmi._RMIConnectionImpl_Tie._invoke +javax/management/remote/mandatory/threads/ExecutorTest.java generic-all + +# Linux 32bit Fedora 9, IllegalStateException +javax/management/monitor/RuntimeExceptionTest.java generic-all + +# Problems with rmi connection, othervm +javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java generic-all + +# Fails with port already in use +sun/management/jmxremote/bootstrap/SSLConfigFilePermissionTest.sh generic-all + +# Fails with port already in use +sun/management/jmxremote/bootstrap/RmiRegistrySslTest.sh generic-all + +# Windows, connection can't last that long +javax/management/eventService/LeaseTest.java generic-all + +# Linux othervm, X64, java.lang.Exception: Failed: ratio=102.4027795593753 +javax/management/remote/mandatory/notif/ListenerScaleTest.java generic-all + +# Windows run seems to have triggered a hotspot gc error (see 6801625) +com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.sh generic-all + +# rmi problem? othervm, java.lang.reflect.UndeclaredThrowableException +javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java generic-all + +# Linux Fedora 9 32bit NPE in rmi server somehere??? othervm +javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java generic-all + +# Times out on solaris sparc, with othervm +javax/management/eventService/AddRemoveListenerTest.java generic-all + +# Linux i586 and x64 -server, timed out waiting for threads to expire? othervm +javax/management/eventService/EventClientThreadTest.java generic-all + +# Linux i586 -server, Expected to receive 20, but got 21, othervm +# Fails on Linux X64 -server 20!=21 +javax/management/eventService/FetchingTest.java generic-all + +# NPE on windows 2000 i586 -client and -server +javax/management/eventService/CustomForwarderTest.java windows-all + +# Windows i586 failure, callback did not complete +javax/management/eventService/LeaseManagerDeadlockTest.java windows-all + +# Port already in use +sun/management/jmxremote/bootstrap/LocalManagementTest.sh generic-all + +# Failed to initialize connector (also overflowing jtreg io buffers) +sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh generic-all +sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh generic-all + +# Windows X64, java.lang.IllegalStateException +javax/management/monitor/AttributeArbitraryDataTypeTest.java generic-all + +############################################################################ + +# jdk_math + +# Problems with rounding add failures on solaris-sparcv9 and -server +java/math/BigDecimal/AddTests.java solaris-sparcv9 + +# Problems on windows with samevm, missing inputstream close()? +# Also times out on solaris-sparcv9 -server +java/math/BigInteger/BigIntegerTest.java generic-all + +# Should be samevm? But seems problematic with samevm on windows +java/math/BigInteger/ModPow65537.java generic-all + +############################################################################ + +# jdk_misc + +# On Windows com.sun.java.swing.plaf.gtk does not exist, always fails there +com/sun/java/swing/plaf/gtk/Test6635110.java windows-all + +# Need to be marked othervm, or changed to be samevm safe +com/sun/jndi/ldap/ReadTimeoutTest.java generic-all +com/sun/jndi/rmi/registry/RegistryContext/UnbindIdempotent.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +com/sun/org/apache/xml/internal/security/transforms/ClassLoaderTest.java generic-all + +# Solaris sparc and others, exception in initializer +javax/imageio/CachePremissionsTest/CachePermissionsTest.java generic-all + +# Leaves file rgba_* open, fails with windows samevm +javax/imageio/plugins/png/PngOutputTypeTest.java generic-all + +# Suspect test.png file is left open, windows samevm problems +javax/imageio/plugins/png/ITXtTest.java generic-all + +# Solaris sparc and others, failed to compile testcase +javax/imageio/metadata/DOML3Node.java generic-all + +# One of these tests is leaving file IMGP1001.JPG open, windows samevm +javax/imageio/plugins/jpeg/ConcurrentReadingTest.java generic-all +javax/imageio/plugins/jpeg/ReadingInterruptionTest.java generic-all + +# One of these files is missing a close on writer_* files, windows samevm +javax/imageio/plugins/jpeg/ConcurrentWritingTest.java generic-all +javax/imageio/plugins/jpeg/WritingInterruptionTest.java generic-all + +# Leaving file test.jpg open, windows samevm +javax/imageio/plugins/jpeg/ReadAsGrayTest.java generic-all + +# Missing close on file wbmp*, windows samevm +javax/imageio/plugins/wbmp/CanDecodeTest.java generic-all + +# Exclude all javax/print tests, even if they passed, they may need samevm work + +# Times out on solaris-sparc, sparcv9, x64 -server, some on i586 -client +javax/print/attribute/autosense/PrintAutoSenseData.java generic-all +javax/print/attribute/Chroma.java generic-all +javax/print/attribute/CollateAttr.java generic-all +javax/print/attribute/PSCopiesFlavorTest.java generic-all +javax/print/LookupServices.java generic-all +javax/print/TestRaceCond.java generic-all + +# These tests really require a printer (might all be windows only tests?) +javax/print/CheckDupFlavor.java generic-all +javax/print/PrintSE/PrintSE.sh generic-all +javax/print/attribute/ChromaticityValues.java generic-all +javax/print/attribute/GetCopiesSupported.java generic-all +javax/print/attribute/SidesPageRangesTest.java generic-all +javax/print/attribute/SupportedPrintableAreas.java generic-all + +# Only print test left, excluding just because all print tests have been +javax/print/attribute/MediaMappingsTest.java generic-all + +############################################################################ + +# jdk_net + +# Suspect many of these tests auffer from using fixed ports, no concrete +# evidence. + +# Fails on OpenSolaris, BindException unexpected +java/net/BindException/Test.java generic-all + +# Fails on OpenSolaris, times out +java/net/MulticastSocket/SetOutgoingIf.java generic-all + +# Timed out on Solaris 10 X86. +com/sun/net/httpserver/Test3.java generic-all + +# Exception in test on windows +com/sun/net/httpserver/bugs/B6373555.java windows-all + +# One of these pollutes the samevm on Linux, too many open files, kills jtreg +com/sun/net/httpserver/bugs/B6339483.java generic-all +com/sun/net/httpserver/bugs/B6341616.java generic-all + +# Suspects in cascading samevm problem, solaris 11 i586 (needs othervm?) +# Suspect use of setHttps*()? +com/sun/net/httpserver/SelCacheTest.java generic-all +com/sun/net/httpserver/Test1.java generic-all +com/sun/net/httpserver/Test12.java generic-all +com/sun/net/httpserver/Test13.java generic-all +com/sun/net/httpserver/Test6a.java generic-all +com/sun/net/httpserver/Test7a.java generic-all +com/sun/net/httpserver/Test8a.java generic-all +com/sun/net/httpserver/Test9.java generic-all +com/sun/net/httpserver/Test9a.java generic-all + +# 10,000 connections, fails on Linux and makes tests&jtreg fail with samevm +com/sun/net/httpserver/bugs/B6361557.java generic-all + +# Address already in use with samevm? Always? Solaris sparc, probably ports +java/net/Authenticator/B4933582.sh generic-all +java/net/DatagramSocket/SendSize.java generic-all + +# Solaris 11: exception wrong address??? +java/net/Inet6Address/B6558853.java generic-all + +# Not closing stream on file i6a1, windows samevm problem +java/net/Inet6Address/serialize/Serialize.java generic-all + +# Linux x64 fails "network unreachable"? +java/net/ipv6tests/TcpTest.java generic-all + +# Linux i586, fails with unexpected output +java/net/MulticastSocket/NoLoopbackPackets.java linux-i586 + +# Times out on windows x64, fails with samevm on solaris 11 i586 +java/net/ServerSocket/AcceptCauseFileDescriptorLeak.java generic-all + +# Address already in use +java/net/DatagramSocket/DatagramTimeout.java generic-all + +# Fails on windows, takes too long and fails +# Solaris 10 sparcv9, samevm, java.lang.Exception: Takes too long. Dead lock +java/net/Socket/DeadlockTest.java generic-all + +# Linux i586 address already in use or connection error, samevm issues +java/net/Socket/AccurateTimeout.java generic-all +java/net/Socket/asyncClose/BrokenPipe.java generic-all +java/net/Socket/CloseAvailable.java generic-all +java/net/Socket/FDClose.java generic-all + +# Linux X64 address already in use, samevm issues +java/net/Socket/LingerTest.java generic-all +java/net/Socket/LinkLocal.java generic-all +java/net/Socket/NullHost.java generic-all +java/net/Socket/ProxyCons.java generic-all +java/net/Socket/ReadTimeout.java generic-all + +# Linux X64 address already in use, samevm issues +java/net/Socket/SetReceiveBufferSize.java generic-all + +# Linux i586 address already in use or connection error, samevm issues +java/net/Socket/setReuseAddress/Basic.java generic-all +java/net/Socket/setReuseAddress/Restart.java generic-all + +# Linux X64 address already in use, samevm issues +java/net/Socket/SetSoLinger.java generic-all + +# Address already in use, windows samevm +java/net/Socket/Timeout.java generic-all + +# Linux X64 address already in use, samevm issues +java/net/Socket/ShutdownBoth.java generic-all +java/net/Socket/SoTimeout.java generic-all +java/net/Socket/TestClose.java generic-all +java/net/Socket/UrgentDataTest.java generic-all +java/net/SocketInputStream/SocketClosedException.java generic-all +java/net/SocketInputStream/SocketTimeout.java generic-all + +# Linux i586, address already in use or timeout, samevm issues +java/net/URLConnection/B5052093.java generic-all +java/net/URLConnection/contentHandler/UserContentHandler.java generic-all +java/net/URLConnection/DisconnectAfterEOF.java generic-all +java/net/URLConnection/HandleContentTypeWithAttrs.java generic-all +java/net/URLConnection/Responses.java generic-all +java/net/URLConnection/TimeoutTest.java generic-all +java/net/URLConnection/ZeroContentLength.java generic-all + +# Solaris 11 i586 fails with samevm, not sure why +java/net/Authenticator/B4769350.java generic-all +java/net/HttpURLConnection/HttpResponseCode.java generic-all +java/net/ResponseCache/B6181108.java generic-all +java/net/ResponseCache/ResponseCacheTest.java generic-all +java/net/URL/GetContent.java generic-all +java/net/URL/TestIPv6Addresses.java generic-all +java/net/URLClassLoader/HttpTest.java generic-all +java/net/URLConnection/HttpContinueStackOverflow.java generic-all +java/net/URLConnection/Redirect307Test.java generic-all +java/net/URLConnection/RedirectLimit.java generic-all +java/net/URLConnection/ResendPostBody.java generic-all +java/net/URL/OpenStream.java generic-all +java/net/URLClassLoader/ClassLoad.java generic-all +java/net/URLConnection/SetIfModifiedSince.java generic-all +java/net/URLConnection/URLConnectionHeaders.java generic-all + +# Linux i586 Connection refused or address already in use, samevm issues +sun/net/ftp/B6427768.java generic-all +sun/net/ftp/FtpGetContent.java generic-all +sun/net/ftp/FtpURL.java generic-all + +# Failed on solaris 10 i586, Exception: should have gotten HttpRetryException? +sun/net/www/http/ChunkedOutputStream/Test.java generic-all + +# Trouble cleaning up threads in samevm mode on solaris 11 i586 +sun/net/www/http/HttpClient/ProxyTest.java generic-all +sun/net/www/http/ChunkedInputStream/ChunkedEncodingTest.java generic-all +sun/net/www/http/ChunkedInputStream/ChunkedEncodingWithProgressMonitorTest.java generic-all +sun/net/www/http/HttpClient/B6726695.java generic-all +sun/net/www/http/HttpClient/MultiThreadTest.java generic-all +sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java generic-all + +# Connection refused, windows samevm +sun/net/www/protocol/http/DigestTest.java generic-all + +############################################################################ + +# jdk_nio + +# Suspect many of these tests auffer from using fixed ports, no concrete +# evidence. + +# Fails on OpenSolaris, IllegalStateException: Cannot add or remove addresses +# from a channel that is bound to the wildcard address +com/sun/nio/sctp/SctpChannel/Bind.java generic-all + +# Failed on OpenSolaris, java.lang.AssertionError: Unknown event type +com/sun/nio/sctp/SctpChannel/Receive.java generic-all + +# Triggers a hotspot crash on Fedora 9 32bit -server and Windows X64 samevm +sun/nio/cs/TestUTF8.java generic-all + +# Solaris sparc, socket timeout +java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh generic-all + +# Runtime exception on windows X64, samevm mode +java/nio/channels/Selector/WakeupNow.java generic-all + +# Occasional errors, solarix x86, address already in use, othervm mode +java/nio/channels/Selector/SelectorTest.java generic-all + +# Fails on Linux Fedora 9 X64 +sun/nio/cs/FindDecoderBugs.java generic-all + +# Solaris 11 gave assert error and "connection refused", samevm issues? +com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java generic-all + +# Fails with othervm on solaris 11 i586 +com/sun/nio/sctp/SctpChannel/CommUp.java generic-all +com/sun/nio/sctp/SctpChannel/Connect.java generic-all +com/sun/nio/sctp/SctpMultiChannel/Branch.java generic-all +com/sun/nio/sctp/SctpMultiChannel/Send.java generic-all +com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java generic-all + +# Linux 64bit failures. too many files open +java/nio/channels/Selector/HelperSlowToDie.java generic-all + +# Timeouts etc. on Window +java/nio/channels/AsyncCloseAndInterrupt.java windows-all + +# Gets java.lang.ExceptionInInitializerError on windows: (Windows 2000 only?) +java/nio/channels/AsynchronousChannelGroup/Basic.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/Identity.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/Restart.java windows-5.0 +java/nio/channels/AsynchronousDatagramChannel/Basic.java windows-5.0 +java/nio/channels/AsynchronousFileChannel/Lock.java windows-5.0 +java/nio/channels/AsynchronousServerSocketChannel/Basic.java windows-5.0 +java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/Basic.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/Leaky.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/StressLoopback.java windows-5.0 +java/nio/channels/Channels/Basic2.java windows-5.0 + +# Solaris sparc timeout +java/nio/channels/DatagramChannel/Connect.java generic-all + +# Solaris i586 timeouts +java/nio/channels/DatagramChannel/EmptyBuffer.java solaris-all + +# Failed loopback connection? On windows 32bit? +# Considered a stress test, can consume all resources. +java/nio/channels/Selector/LotsOfChannels.java generic-all + +# Solaris sparcv9, just fails with exception +java/nio/channels/Selector/OpRead.java solaris-sparc + +# Windows i586 client, crashed hotspot? Unpredictable +# Considered a stress test, can consume all resources. +java/nio/channels/Selector/RegAfterPreClose.java generic-all + +# Solaris i586, cannot assign address, samevm issues +java/nio/channels/Selector/SelectorLimit.java generic-all + +# Socket timeout windows X64 +java/nio/channels/ServerSocketChannel/AdaptServerSocket.java windows-all + +# Timeouts etc. on Window +java/nio/channels/SocketChannel/ConnectState.java windows-all +java/nio/channels/SocketChannel/FinishConnect.java windows-all + +# Need to be marked othervm, or changed to be samevm safe +java/nio/channels/SocketChannel/OpenLeak.java generic-all + +# Gets java.net.BindException alot (static port number?) +java/nio/channels/SocketChannel/VectorIO.java generic-all + +# Solaris i586 java.net.BindExceptions +java/nio/channels/SocketChannel/VectorParams.java solaris-all + +# Linux i586 address already in use, samevm issues +java/nio/channels/SocketChannel/Write.java generic-all + +# Fails on all platforms due to overlap of JDK jar file contents: +sun/nio/cs/Test4200310.sh generic-all + +# Depends on motif packages that do not exist all the time: +sun/nio/cs/TestX11CNS.java generic-all + +############################################################################ + +# jdk_rmi + +# Port already in use, fails on sparc, othervm +java/rmi/reliability/benchmark/runRmiBench.sh generic-all + +# Already in use port issues? othervm solaris +java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java generic-all +java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java generic-all + +# Address already in use, othervm mode, solaris +java/rmi/activation/Activatable/elucidateNoSuchMethod/ElucidateNoSuchMethod.java generic-all +java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java generic-all + +# Registry already running on port, solaris +java/rmi/Naming/legalRegistryNames/LegalRegistryNames.java generic-all + +# Fails on Linux 32 and 64bit -server?, impl not garbage collected??? +java/rmi/transport/pinLastArguments/PinLastArguments.java generic-all + +# Times out on solaris sparc +java/rmi/server/RemoteServer/AddrInUse.java generic-all + +# Connection error on Windows i586 -server +# Also connection errors in othervm on Solaris 10 sparc, same port??? +sun/rmi/transport/tcp/DeadCachedConnection.java generic-all + +# Connection errors in othervm on Solaris 10 sparc, same port??? +java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java generic-all +java/rmi/activation/Activatable/checkAnnotations/CheckAnnotations.java generic-all +java/rmi/activation/Activatable/checkImplClassLoader/CheckImplClassLoader.java generic-all +java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java generic-all +java/rmi/activation/Activatable/createPrivateActivable/CreatePrivateActivatable.java generic-all +java/rmi/activation/Activatable/downloadParameterClass/DownloadParameterClass.java generic-all +java/rmi/activation/Activatable/extLoadedImpl/ext.sh generic-all +java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java generic-all +java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java generic-all +java/rmi/activation/Activatable/nestedActivate/NestedActivate.java generic-all +java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java generic-all +java/rmi/activation/Activatable/restartLatecomer/RestartLatecomer.java generic-all +java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java generic-all +java/rmi/activation/Activatable/unregisterInactive/UnregisterInactive.java generic-all +java/rmi/activation/ActivateFailedException/activateFails/ActivateFails.java generic-all +java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java generic-all +java/rmi/activation/ActivationSystem/activeGroup/IdempotentActiveGroup.java generic-all +java/rmi/reliability/juicer/AppleUserImpl.java generic-all +java/rmi/server/RMISocketFactory/useSocketFactory/unicast/UseCustomSocketFactory.java generic-all +java/rmi/server/UnicastRemoteObject/keepAliveDuringCall/KeepAliveDuringCall.java generic-all +java/rmi/transport/handshakeTimeout/HandshakeTimeout.java generic-all +java/rmi/activation/Activatable/restartService/RestartService.java generic-all +java/rmi/activation/ActivationSystem/modifyDescriptor/ModifyDescriptor.java generic-all +java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java generic-all +java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java generic-all +java/rmi/activation/CommandEnvironment/SetChildEnv.java generic-all +java/rmi/registry/classPathCodebase/ClassPathCodebase.java generic-all +java/rmi/registry/reexport/Reexport.java generic-all +java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java generic-all +java/rmi/server/Unreferenced/leaseCheckInterval/LeaseCheckInterval.java generic-all +java/rmi/server/Unreferenced/unreferencedContext/UnreferencedContext.java generic-all +java/rmi/server/useCustomRef/UseCustomRef.java generic-all +java/rmi/transport/checkFQDN/CheckFQDN.java generic-all +java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java generic-all +java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java generic-all +java/rmi/server/RMISocketFactory/useSocketFactory/registry/UseCustomSocketFactory.java generic-all +java/rmi/server/UnicastRemoteObject/unexportObject/UnexportLeak.java generic-all + +############################################################################ + +# jdk_security + +# Run too slow on Solaris 10 sparc +sun/security/ssl/com/sun/net/ssl/internal/ssl/InputRecord/SSLSocketTimeoutNulls.java solaris-sparc +sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/ClientTimeout.java solaris-sparc +sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/ServerTimeout.java solaris-sparc +sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/ReadTimeout.java solaris-sparc +sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/NotifyHandshakeTest.sh solaris-sparc +sun/security/tools/keytool/AltProviderPath.sh solaris-sparc + +# Solaris 10 sparc, passed/failed confusion? java.security.ProviderException: update() failed +sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/AsyncSSLSocketClose.java generic-all + +# Seem really slow on Solaris sparc, being excluded just for timing reasons +sun/security/tools/jarsigner/AlgOptions.sh solaris-sparc +sun/security/tools/jarsigner/nameclash.sh solaris-sparc +sun/security/krb5/auto/basic.sh solaris-sparc +sun/security/provider/PolicyFile/getinstance/getinstance.sh solaris-sparc +sun/security/tools/jarsigner/samename.sh solaris-sparc + +# Timed out, Solaris 10 64bit sparcv9 +com/sun/crypto/provider/Cipher/DES/PaddingTest.java generic-all + +# Othervm, sparc, NoRouteToHostException: Cannot assign requested address +sun/security/ssl/javax/net/ssl/NewAPIs/SessionCacheSizeTests.java generic-all + +# ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_DEVICE_ERROR +# Does not seem to run on windows machines? dll missing? +sun/security/pkcs11/rsa/TestKeyPairGenerator.java generic-all + +# Times out on windows X64, othervm mode +# Solaris sparc and sparcv9 -server, timeout +sun/security/ssl/javax/net/ssl/NewAPIs/SessionTimeOutTests.java generic-all + +# Failed on solaris 10 sparc, othervm mode, "js.jks: No such file or directory" +# Also, cannot verify signature on solaris i586 -server +sun/security/tools/jarsigner/concise_jarsigner.sh generic-all + +# Various failures on Linux Fedora 9 X64, othervm mode +lib/security/cacerts/VerifyCACerts.java generic-all +sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java generic-all +sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java generic-all +sun/security/tools/jarsigner/oldsig.sh generic-all + +# Various failures on Linux Fedora 9 X64, othervm mode +# Does not seem to run on windows machines? dll missing? +sun/security/ssl/sanity/interop/ClientJSSEServerJSSE.java generic-all + +# Linux i586 -server, buffer too short to hold shared secret? +com/sun/crypto/provider/KeyAgreement/DHKeyAgreement2.java generic-all + +# Solaris sparcv9: Failed to parse input emptysubject.jks: No such file or directory +sun/security/tools/keytool/emptysubject.sh generic-all + +# Timeout on solaris-sparcv9 or exception thrown +com/sun/crypto/provider/Cipher/RSA/TestOAEP_KAT.java solaris-all + +# File 6535697.test input stream left open? windows samevm +java/security/cert/CertificateFactory/openssl/OpenSSLCert.java generic-all + +# Leaving file open: SerialVersion.current, windows samevm +java/security/BasicPermission/SerialVersion.java generic-all + +# Solaris 11 i586, these all fail with samevm, need to be othervm??? +java/security/BasicPermission/NullOrEmptyName.java generic-all + +# Suspect missing close() on file PermClass.current, windows samevm cascade +java/security/BasicPermission/PermClass.java generic-all + +# Solaris 11 i586, these all fail with samevm, need to be othervm??? +java/security/KeyPairGenerator/Failover.java generic-all +java/security/Provider/DefaultPKCS11.java generic-all +java/security/SecureClassLoader/DefineClassByteBuffer.java generic-all +java/security/SecureRandom/GetAlgorithm.java generic-all +java/security/Security/removing/RemoveProviders.java generic-all +java/security/Signature/ByteBuffers.java generic-all +java/security/Signature/NONEwithRSA.java generic-all +java/security/Signature/SignWithOutputBuffer.java generic-all +java/security/Signature/TestInitSignWithMyOwnRandom.java generic-all +java/security/UnresolvedPermission/AccessorMethods.java generic-all +java/security/UnresolvedPermission/Equals.java generic-all + +# Do not seem to run on windows machines? dll missing? +sun/security/krb5/auto/IgnoreChannelBinding.java windows-all + +# Fails on OpenSolaris, missing classes, slow on Solaris sparc +sun/security/ec/TestEC.java generic-all + +# Problems with windows x64 +sun/security/mscapi/IsSunMSCAPIAvailable.sh windows-x64 +sun/security/mscapi/RSAEncryptDecrypt.sh windows-x64 + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/Cipher/ReinitCipher.java windows-all +sun/security/pkcs11/Cipher/TestRSACipher.java windows-all +sun/security/pkcs11/Cipher/TestRSACipherWrap.java windows-all +sun/security/pkcs11/Cipher/TestSymmCiphers.java windows-all +sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java windows-all + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/ec/ReadCertificates.java windows-all +sun/security/pkcs11/ec/ReadPKCS12.java windows-all +sun/security/pkcs11/ec/TestCurves.java windows-all +sun/security/pkcs11/ec/TestECDH.java windows-all +sun/security/pkcs11/ec/TestECDSA.java windows-all +sun/security/pkcs11/ec/TestECGenSpec.java windows-all +sun/security/pkcs11/ec/TestKeyFactory.java windows-all +sun/security/pkcs11/fips/TrustManagerTest.java windows-all + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/KeyAgreement/TestShort.java windows-all +sun/security/pkcs11/KeyGenerator/DESParity.java windows-all + +# Exception in test solaris-sparc -client -server, no windows +sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java windows-all solaris-all + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/KeyStore/Basic.sh windows-all +sun/security/pkcs11/KeyStore/ClientAuth.sh windows-all + +# Solaris sparc client, fails to compile? +sun/security/pkcs11/KeyStore/SecretKeysBasic.sh solaris-all + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/Mac/ReinitMac.java windows-all +sun/security/pkcs11/MessageDigest/ByteBuffers.java windows-all +sun/security/pkcs11/MessageDigest/DigestKAT.java windows-all +sun/security/pkcs11/MessageDigest/ReinitDigest.java windows-all +sun/security/pkcs11/Provider/ConfigQuotedString.sh windows-all +sun/security/pkcs11/Provider/Login.sh windows-all +sun/security/pkcs11/rsa/KeyWrap.java windows-all +sun/security/pkcs11/rsa/TestCACerts.java windows-all +sun/security/pkcs11/rsa/TestKeyFactory.java windows-all +sun/security/pkcs11/rsa/TestSignatures.java windows-all +sun/security/pkcs11/SampleTest.java windows-all +sun/security/pkcs11/Secmod/AddPrivateKey.java windows-all +sun/security/pkcs11/Secmod/AddTrustedCert.java windows-all +sun/security/pkcs11/Secmod/Crypto.java windows-all +sun/security/pkcs11/Secmod/GetPrivateKey.java windows-all +sun/security/pkcs11/Secmod/JksSetPrivateKey.java windows-all +sun/security/pkcs11/Secmod/TrustAnchors.java windows-all +sun/security/pkcs11/SecureRandom/Basic.java windows-all +sun/security/pkcs11/Serialize/SerializeProvider.java windows-all +sun/security/pkcs11/Signature/ByteBuffers.java windows-all +sun/security/pkcs11/Signature/ReinitSignature.java windows-all +sun/security/pkcs11/Signature/TestDSA.java windows-all +sun/security/pkcs11/tls/TestKeyMaterial.java windows-all +sun/security/pkcs11/tls/TestMasterSecret.java windows-all +sun/security/pkcs11/tls/TestPremaster.java windows-all +sun/security/pkcs11/tls/TestPRF.java windows-all + +# Fails on OpenSolaris java.net.BindException: Address already in use +sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java generic-all + +# Timeout on solaris-sparcv9 or ArrayIndexOutOfBoundsException? +sun/security/rsa/TestKeyPairGeneratorLength.java solaris-all +sun/security/rsa/TestSignatures.java solaris-all + +# Timeout on solaris-sparc and i586 and x64, -client and -server +sun/security/ssl/com/sun/net/ssl/internal/ssl/InputRecord/InterruptedIO.java solaris-all + +# Do not seem to run on windows machines? dll missing? +sun/security/tools/jarsigner/emptymanifest.sh windows-all + +# Files does not exist or no encoding? solaris-sparcv9 +sun/security/tools/keytool/importreadall.sh solaris-all +sun/security/tools/keytool/selfissued.sh solaris-all + +############################################################################ + +# jdk_swing (not using samevm) + +# Fails on solaris 10 sparc, throws RuntimeException that just says "failed" +javax/swing/JLabel/6501991/bug6501991.java generic-all + +# Fails on solaris 11 i586, with othervm +javax/swing/JFileChooser/6570445/bug6570445.java generic-all +javax/swing/JFileChooser/6738668/bug6738668.java generic-all +javax/swing/JPopupMenu/6675802/bug6675802.java generic-all +javax/swing/system/6799345/TestShutdown.java generic-all + +############################################################################ + +# jdk_text + +# Linux x64 occasional errors, no details +java/text/Bidi/Bug6665028.java linux-x64 + +############################################################################ + +# jdk_tools + +# Some of the tools tests kind of require "othervm" or if they don't will +# always be firing up another VM anyway due to the nature of tools testing. +# So most if not all tools tests are now being run with "othervm" mode. +# Some of these tools tests have a tendency to use fixed ports, bad idea. + +# Solaris 10 client x86, java.lang.IndexOutOfBoundsException resumer Interrupted +com/sun/jdi/SimulResumerTest.java generic-all + +# Output of jps differs from expected output. +# Invalid argument count on solaris-sparc and x64 +sun/tools/jstatd/jstatdPort.sh generic-all + +# othervm mode, Could not synchronize with target +sun/tools/jps/jps-l_1.sh generic-all +sun/tools/jps/jps-l_2.sh generic-all +sun/tools/jps/jps-lm.sh generic-all +sun/tools/jps/jps-Vvml_2.sh generic-all +sun/tools/jps/jps-m_2.sh generic-all + +# Server name error, port 2098 problem? +sun/tools/jstatd/jstatdServerName.sh generic-all + +# Solaris, handshake failed, othervm mode +com/sun/jdi/RedefineException.sh generic-all + +# These tests fail on solaris sparc, all the time +com/sun/servicetag/DeleteServiceTag.java generic-all +com/sun/servicetag/DuplicateNotFound.java generic-all +com/sun/servicetag/FindServiceTags.java generic-all +com/sun/servicetag/InstanceUrnCheck.java generic-all +com/sun/servicetag/InvalidRegistrationData.java generic-all +com/sun/servicetag/InvalidServiceTag.java generic-all +com/sun/servicetag/JavaServiceTagTest.java generic-all +com/sun/servicetag/JavaServiceTagTest1.java generic-all +com/sun/servicetag/NewRegistrationData.java generic-all +com/sun/servicetag/SystemRegistryTest.java generic-all +com/sun/servicetag/TestLoadFromXML.java generic-all +com/sun/servicetag/UpdateServiceTagTest.java generic-all +com/sun/servicetag/ValidRegistrationData.java generic-all + +# Problems on windows, jmap.exe hangs? +com/sun/tools/attach/BasicTests.sh windows-all + +# Fails on Solaris 10 sparc, in othervm mode, throws unexpected exception +sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all + +# Unexpected Monitor Exception, solaris sparc -client +sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh generic-all + +# Probably should be samevm, but seem to cause errors even in othervm at times +sun/tools/jhat/HatHeapDump1Test.java generic-all + +# Problems on windows, jmap.exe hangs? (these run jmap) +sun/tools/jmap/Basic.sh windows-all + +# Invalid argument count on solaris-sparc and x64 +sun/tools/jstatd/jstatdDefaults.sh solaris-all + +# Solaris sparcv9, jps output does not match, x64 different +sun/tools/jstatd/jstatdExternalRegistry.sh solaris-all + +# Probably should be samevm, but seem to cause errors even in othervm at times +sun/tools/native2ascii/NativeErrors.java generic-all + +# Solaris 10 sparc 32bit -client, java.lang.AssertionError: Some tests failed +tools/jar/JarEntryTime.java generic-all + +# Times out on sparc? +tools/launcher/VersionCheck.java generic-all + +# These tests fail on solaris sparc, all the time +tools/jar/ChangeDir.java generic-all + +# Cannot write jar +# Also, possible problems on windows, jmap.exe hangs? +tools/jar/index/MetaInf.java windows-all + +############################################################################ + +# jdk_util + +# Assert error, failures, on Linux Fedora 9 -server +# Windows samevm failure, assert error "Passed = 134, failed = 2" +java/util/Arrays/ArrayObjectMethods.java generic-all + +# Windows 2000, -client, samevm, java.lang.Error: Completed != 2 +java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java generic-all + +# Windows X64, Executor Stuck samevm mode: +java/util/concurrent/FutureTask/BlockingTaskExecutor.java generic-all + +# Problems on windows, jmap.exe hangs? (these run jmap), fails on Solaris 10 x86 +java/util/concurrent/locks/Lock/TimedAcquireLeak.java generic-all + +# Solaris sparc client, some failures, "1 not equal to 3"? +# also Linux problems with samevm mode, -server linux i586? 1 not equal to 3? +java/util/concurrent/Executors/AutoShutdown.java generic-all + +# Fails on solaris-sparc -server (Set not equal to copy. 1) +java/util/EnumSet/EnumSetBash.java solaris-sparc + +# Failing to close an input stream? "foo", triggers samevm windows failures +java/util/Formatter/Constructors.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/util/Locale/Bug4175998Test.java generic-all +java/util/Locale/Bug4184873Test.java generic-all +java/util/Locale/LocaleTest.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/util/logging/GetGlobalTest.java generic-all +java/util/logging/LoggerSubclass.java generic-all +java/util/logging/LoggingDeadlock.java generic-all +java/util/logging/LoggingDeadlock2.java generic-all +java/util/logging/LoggingMXBeanTest.java generic-all +java/util/logging/LoggingMXBeanTest2.java generic-all +java/util/logging/LoggingNIOChange.java generic-all +java/util/logging/ParentLoggersTest.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/util/ResourceBundle/Bug4168625Test.java generic-all +java/util/ResourceBundle/Bug6359330.java generic-all +java/util/ResourceBundle/TestBug4179766.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/util/WeakHashMap/GCDuringIteration.java generic-all + +# Possible missing input stream close()? Causes samevm issues on windows +java/util/zip/InfoZip.java generic-all + +# Missing a close() on file Test0.zip? windows samevm cascade problem +java/util/zip/ZipFile/Comment.java generic-all + +# Suspect missing close() on bad*.zip files, windows cascade errors with samevm +java/util/zip/ZipFile/CorruptedZipFiles.java generic-all + +# Should be samevm but causes problems with samevm, no details: +java/util/zip/ZipFile/ManyEntries.java generic-all + +############################################################################ + diff --git a/jdk/test/demo/jvmti/DemoRun.java b/jdk/test/demo/jvmti/DemoRun.java index 1958a1effe2..7a1a42d6253 100644 --- a/jdk/test/demo/jvmti/DemoRun.java +++ b/jdk/test/demo/jvmti/DemoRun.java @@ -145,7 +145,7 @@ public class DemoRun { */ int nvm_options = 0; if ( vm_options != null ) nvm_options = vm_options.length; - String cmd[] = new String[1 + (d64?1:0) + 5 + nvm_options]; + String cmd[] = new String[1 + (d64?1:0) + 7 + nvm_options]; String cmdLine; int exitStatus; int i,j; @@ -154,6 +154,10 @@ public class DemoRun { cmdLine = ""; cmdLine += (cmd[i++] = java); cmdLine += " "; + cmdLine += (cmd[i++] = "-cp"); + cmdLine += " "; + cmdLine += (cmd[i++] = cdir); + cmdLine += " "; cmdLine += (cmd[i++] = "-Dtest.classes=" + cdir); if ( d64 ) { cmdLine += " "; diff --git a/jdk/test/java/awt/GraphicsDevice/CloneConfigsTest.java b/jdk/test/java/awt/GraphicsDevice/CloneConfigsTest.java new file mode 100644 index 00000000000..44eec545dda --- /dev/null +++ b/jdk/test/java/awt/GraphicsDevice/CloneConfigsTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6822057 + * + * @summary Test verifies that list of supported graphics configurations + * can not be changed via modification of elements of an array + * returned by getConfiguration() method. + * + * @run main CloneConfigsTest + * @run main/othervm -Dsun.java2d.opengl=True CloneConfigsTest + * @run main/othervm -Dsun.java2d.d3d=true CloneConfigsTest + * @run main/othervm -Dsun.java2d.noddraw=true CloneConfigsTest + */ + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; + +public class CloneConfigsTest { + + public static void main(String[] args) { + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + + GraphicsDevice[] devices = env.getScreenDevices(); + + GraphicsConfiguration c = new TestConfig(); + + for (GraphicsDevice gd : devices) { + System.out.println("Device: " + gd); + + GraphicsConfiguration[] configs = gd.getConfigurations(); + + for (int i = 0; i < configs.length; i++) { + GraphicsConfiguration gc = configs[i]; + System.out.println("\tConfig: " + gc); + + configs[i] = c; + } + + // verify whether array of configs was modified + configs = gd.getConfigurations(); + for (GraphicsConfiguration gc : configs) { + if (gc == c) { + throw new RuntimeException("Test failed."); + } + } + System.out.println("Test passed."); + } + } + + private static class TestConfig extends GraphicsConfiguration { + + @Override + public GraphicsDevice getDevice() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BufferedImage createCompatibleImage(int width, int height) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ColorModel getColorModel() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ColorModel getColorModel(int transparency) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AffineTransform getDefaultTransform() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AffineTransform getNormalizingTransform() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Rectangle getBounds() { + throw new UnsupportedOperationException("Not supported yet."); + } + + } + +} diff --git a/jdk/test/java/lang/ClassLoader/UninitializedParent.java b/jdk/test/java/lang/ClassLoader/UninitializedParent.java new file mode 100644 index 00000000000..155ae179bed --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/UninitializedParent.java @@ -0,0 +1,68 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6636650 + * @summary Uninitialized class loaders should not be a parent of other + * class loaders. + */ + + +import java.net.*; + +public class UninitializedParent { + private static ClassLoader loader; + public static void main(String[] args) throws Exception { + System.setSecurityManager(new SecurityManager()); + + // Create an uninitialized class loader + try { + new ClassLoader(null) { + @Override + protected void finalize() { + loader = this; + } + }; + } catch (SecurityException exc) { + // Expected + } + System.gc(); + System.runFinalization(); + + // if 'loader' isn't null, need to ensure that it can't be used as + // parent + if (loader != null) { + try { + // Create a class loader with 'loader' being the parent + URLClassLoader child = URLClassLoader.newInstance + (new URL[0], loader); + throw new RuntimeException("Test Failed!"); + } catch (SecurityException se) { + System.out.println("Test Passed: Exception thrown"); + } + } else { + System.out.println("Test Passed: Loader is null"); + } + } +} diff --git a/jdk/test/java/nio/Buffer/Basic-X.java b/jdk/test/java/nio/Buffer/Basic-X.java.template similarity index 100% rename from jdk/test/java/nio/Buffer/Basic-X.java rename to jdk/test/java/nio/Buffer/Basic-X.java.template diff --git a/jdk/test/java/nio/Buffer/CopyDirect-X-Memory.java b/jdk/test/java/nio/Buffer/CopyDirect-X-Memory.java.template similarity index 100% rename from jdk/test/java/nio/Buffer/CopyDirect-X-Memory.java rename to jdk/test/java/nio/Buffer/CopyDirect-X-Memory.java.template diff --git a/jdk/test/java/nio/Buffer/genBasic.sh b/jdk/test/java/nio/Buffer/genBasic.sh index 84448d90d7e..da5fca5df33 100644 --- a/jdk/test/java/nio/Buffer/genBasic.sh +++ b/jdk/test/java/nio/Buffer/genBasic.sh @@ -26,7 +26,7 @@ javac -d . ../../../../make/tools/src/build/tools/spp/Spp.java gen() { - java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3 Basic$2.java + java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3 Basic$2.java } gen byte Byte Byte diff --git a/jdk/test/java/nio/Buffer/genCopyDirectMemory.sh b/jdk/test/java/nio/Buffer/genCopyDirectMemory.sh index 504470f7586..471df042532 100644 --- a/jdk/test/java/nio/Buffer/genCopyDirectMemory.sh +++ b/jdk/test/java/nio/Buffer/genCopyDirectMemory.sh @@ -26,7 +26,7 @@ javac -d . ../../../../make/tools/src/build/tools/spp/Spp.java > Spp.java gen() { - java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3CopyDirect$2Memory.java + java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3CopyDirect$2Memory.java } gen byte Byte Byte diff --git a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java index 7b947d949e6..dcf0a62531d 100644 --- a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java @@ -34,7 +34,7 @@ import java.io.IOException; public class Unbounded { // number of concurrent completion handlers - static final int CONCURRENCY_COUNT = 512; + static final int CONCURRENCY_COUNT = 256; public static void main(String[] args) throws Exception { // all accepted connections are added to a queue diff --git a/jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java b/jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java index f1d7d5debc6..2d7b6241feb 100644 --- a/jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java +++ b/jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java @@ -73,22 +73,22 @@ class NetworkConfiguration { List addrs = Collections.list(nif.getInetAddresses()); for (InetAddress addr: addrs) { - if (addr instanceof Inet4Address) { - List list = ip4Interfaces.get(nif); - if (list == null) { - list = new LinkedList(); + if (!addr.isAnyLocalAddress()) { + if (addr instanceof Inet4Address) { + List list = ip4Interfaces.get(nif); + if (list == null) { + list = new LinkedList(); + } + list.add(addr); + ip4Interfaces.put(nif, list); + } else if (addr instanceof Inet6Address) { + List list = ip6Interfaces.get(nif); + if (list == null) { + list = new LinkedList(); + } + list.add(addr); + ip6Interfaces.put(nif, list); } - list.add(addr); - ip4Interfaces.put(nif, list); - } - if (addr instanceof Inet6Address) { - List list = ip6Interfaces.get(nif); - if (list == null) { - list = new LinkedList(); - } - list.add(addr); - ip6Interfaces.put(nif, list); - } } } diff --git a/jdk/test/java/nio/channels/FileChannel/Transfer.java b/jdk/test/java/nio/channels/FileChannel/Transfer.java index 15578c3b38e..b511ae6a6d3 100644 --- a/jdk/test/java/nio/channels/FileChannel/Transfer.java +++ b/jdk/test/java/nio/channels/FileChannel/Transfer.java @@ -25,6 +25,7 @@ * @bug 4434723 4482726 4559072 4638365 4795550 5081340 5103988 6253145 * @summary Test FileChannel.transferFrom and transferTo * @library .. + * @run main/timeout=180 Transfer */ import java.io.*; diff --git a/jdk/test/java/nio/channels/Selector/LotsOfCancels.java b/jdk/test/java/nio/channels/Selector/LotsOfCancels.java new file mode 100644 index 00000000000..bbf0be2f1db --- /dev/null +++ b/jdk/test/java/nio/channels/Selector/LotsOfCancels.java @@ -0,0 +1,292 @@ +/* + * Copyright 2009 Google Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Reproduces O(N^2) behavior of JDK6/7 select() call. This happens when + * a selector has many unprocessed updates to its interest set (e.g. adding + * OP_READ on a bunch of newly accepted sockets). The O(N^2) is triggered + * by cancelling a number of selection keys (or just closing a few sockets). + * In this case, select() will first go through the list of cancelled keys + * and try to deregister them. That deregistration is O(N^2) over the list + * of unprocessed updates to the interest set. + * + *

    This O(N^2) behavior is a BUG in JVM and should be fixed. + * + *

    The test first creates initCount connections, and adds them + * to the server epoll set. It then creates massCount connections, + * registers interest (causing updateList to be populated with massCount*2 + * elements), but does not add them to epoll set (that would've cleared + * updateList). The test then closes initCount connections, thus populating + * deregistration queue. The subsequent call to selectNow() will first process + * deregistration queue, performing O(N^2) over updateList size, + * equal to massCount * 2. + * + *

    Note that connect rate is artificially slowed down to compensate + * for what I believe is a Linux bug, where too high of a connection rate + * ends up in SYN's being dropped and then slow retransmits. + * + * @author Igor Chernyshev + */ +public class LotsOfCancels { + + static long testStartTime; + + public static void main(String[] args) throws Exception { + // the final select should run in less than 1000ms. + runTest(500, 2700, 1000); + } + + static void log(String msg) { + System.out.println(getLogPrefix() + msg); + } + + static String getLogPrefix() { + return durationMillis(testStartTime) + ": "; + } + + /** + * Returns the elapsed time since startNanos, in milliseconds. + * @param startNanos the start time; this must be a value returned + * by {@link System.nanoTime} + */ + static long durationMillis(long startNanos) { + return (System.nanoTime() - startNanos) / (1000L * 1000L); + } + + static void runTest(int initCount, int massCount, int maxSelectTime) + throws Exception { + testStartTime = System.nanoTime(); + + InetSocketAddress address = new InetSocketAddress("127.0.0.1", 7359); + + // Create server channel, add it to selector and run epoll_ctl. + log("Setting up server"); + Selector serverSelector = Selector.open(); + ServerSocketChannel server = ServerSocketChannel.open(); + server.configureBlocking(false); + server.socket().bind(address, 5000); + server.register(serverSelector, SelectionKey.OP_ACCEPT); + serverSelector.selectNow(); + + log("Setting up client"); + ClientThread client = new ClientThread(address); + client.start(); + Thread.sleep(100); + + // Set up initial set of client sockets. + log("Starting initial client connections"); + client.connectClients(initCount); + Thread.sleep(500); // Wait for client connections to arrive + + // Accept all initial client sockets, add to selector and run + // epoll_ctl. + log("Accepting initial connections"); + List serverChannels1 = + acceptAndAddAll(serverSelector, server, initCount); + if (serverChannels1.size() != initCount) { + throw new Exception("Accepted " + serverChannels1.size() + + " instead of " + initCount); + } + serverSelector.selectNow(); + + // Set up mass set of client sockets. + log("Requesting mass client connections"); + client.connectClients(massCount); + Thread.sleep(500); // Wait for client connections to arrive + + // Accept all mass client sockets, add to selector and do NOT + // run epoll_ctl. + log("Accepting mass connections"); + List serverChannels2 = + acceptAndAddAll(serverSelector, server, massCount); + if (serverChannels2.size() != massCount) { + throw new Exception("Accepted " + serverChannels2.size() + + " instead of " + massCount); + } + + // Close initial set of sockets. + log("Closing initial connections"); + closeAll(serverChannels1); + + // Now get the timing of select() call. + log("Running the final select call"); + long startTime = System.nanoTime(); + serverSelector.selectNow(); + long duration = durationMillis(startTime); + log("Init count = " + initCount + + ", mass count = " + massCount + + ", duration = " + duration + "ms"); + + if (duration > maxSelectTime) { + System.out.println + ("\n\n\n\n\nFAILURE: The final selectNow() took " + + duration + "ms " + + "- seems like O(N^2) bug is still here\n\n"); + System.exit(1); + } + } + + static List acceptAndAddAll(Selector selector, + ServerSocketChannel server, + int expected) + throws Exception { + int retryCount = 0; + int acceptCount = 0; + List channels = new ArrayList(); + while (channels.size() < expected) { + SocketChannel channel = server.accept(); + if (channel == null) { + log("accept() returned null " + + "after accepting " + acceptCount + " more connections"); + acceptCount = 0; + if (retryCount < 10) { + // See if more new sockets got stacked behind. + retryCount++; + Thread.sleep(500); + continue; + } + break; + } + retryCount = 0; + acceptCount++; + channel.configureBlocking(false); + channel.register(selector, SelectionKey.OP_READ); + channels.add(channel); + } + // Cause an additional updateList entry per channel. + for (SocketChannel channel : channels) { + channel.register(selector, SelectionKey.OP_WRITE); + } + return channels; + } + + static void closeAll(List channels) + throws Exception { + for (SocketChannel channel : channels) { + channel.close(); + } + } + + static class ClientThread extends Thread { + private final SocketAddress address; + private final Selector selector; + private int connectionsNeeded; + private int totalCreated; + + ClientThread(SocketAddress address) throws Exception { + this.address = address; + selector = Selector.open(); + setDaemon(true); + } + + void connectClients(int count) throws Exception { + synchronized (this) { + connectionsNeeded += count; + } + selector.wakeup(); + } + + @Override + public void run() { + try { + handleClients(); + } catch (Throwable e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void handleClients() throws Exception { + int selectCount = 0; + while (true) { + int createdCount = 0; + synchronized (this) { + if (connectionsNeeded > 0) { + + while (connectionsNeeded > 0 && createdCount < 20) { + connectionsNeeded--; + createdCount++; + totalCreated++; + + SocketChannel channel = SocketChannel.open(); + channel.configureBlocking(false); + channel.connect(address); + if (!channel.finishConnect()) { + channel.register(selector, + SelectionKey.OP_CONNECT); + } + } + + log("Started total of " + + totalCreated + " client connections"); + Thread.sleep(200); + } + } + + if (createdCount > 0) { + selector.selectNow(); + } else { + selectCount++; + long startTime = System.nanoTime(); + selector.select(); + long duration = durationMillis(startTime); + log("Exited clientSelector.select(), loop #" + + selectCount + ", duration = " + duration + "ms"); + } + + int keyCount = -1; + Iterator keys = + selector.selectedKeys().iterator(); + while (keys.hasNext()) { + SelectionKey key = keys.next(); + synchronized (key) { + keyCount++; + keys.remove(); + if (!key.isValid()) { + log("Ignoring client key #" + keyCount); + continue; + } + int readyOps = key.readyOps(); + if (readyOps == SelectionKey.OP_CONNECT) { + key.interestOps(0); + ((SocketChannel) key.channel()).finishConnect(); + } else { + log("readyOps() on client key #" + keyCount + + " returned " + readyOps); + } + } + } + } + } + } +} diff --git a/jdk/test/java/nio/file/Path/CopyAndMove.java b/jdk/test/java/nio/file/Path/CopyAndMove.java index 5894b2894f2..18abbe0de56 100644 --- a/jdk/test/java/nio/file/Path/CopyAndMove.java +++ b/jdk/test/java/nio/file/Path/CopyAndMove.java @@ -25,6 +25,8 @@ * @bug 4313887 6838333 * @summary Unit test for java.nio.file.Path copyTo/moveTo methods * @library .. + * @build CopyAndMove + * @run main/othervm CopyAndMove */ import java.nio.ByteBuffer; diff --git a/jdk/test/java/nio/file/Path/Links.java b/jdk/test/java/nio/file/Path/Links.java index 8ffd89fb691..aa88e37a702 100644 --- a/jdk/test/java/nio/file/Path/Links.java +++ b/jdk/test/java/nio/file/Path/Links.java @@ -26,6 +26,8 @@ * @summary Unit test for java.nio.file.Path createSymbolicLink, * readSymbolicLink, and createLink methods * @library .. + * @build Links + * @run main/othervm Links */ import java.nio.file.*; diff --git a/jdk/test/java/util/Arrays/Sorting.java b/jdk/test/java/util/Arrays/Sorting.java index 5dfdb491b9c..ecd6ec8970b 100644 --- a/jdk/test/java/util/Arrays/Sorting.java +++ b/jdk/test/java/util/Arrays/Sorting.java @@ -23,11 +23,14 @@ /* * @test - * @bug 6880672 6896573 + * @bug 6880672 6896573 6899694 * @summary Exercise Arrays.sort * @build Sorting * @run main Sorting -shortrun - * @author Vladimir Yaroslavskiy, Josh Bloch, Jon Bentley + * + * @author Vladimir Yaroslavskiy + * @author Jon Bentley + * @author Josh Bloch */ import java.util.Arrays; @@ -35,59 +38,300 @@ import java.util.Random; import java.io.PrintStream; public class Sorting { - static final PrintStream out = System.out; - static final PrintStream err = System.err; + private static final PrintStream out = System.out; + private static final PrintStream err = System.err; - // array lengths used in a long run (default) - static final int[] LONG_RUN = { - 0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000}; + // Array lengths used in a long run (default) + private static final int[] LONG_RUN_LENGTHS = { + 1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000}; - // array lengths used in a short run - static final int[] SHORT_RUN = {0, 1, 2, 3, 21, 55, 1000, 10000, 500000}; + // Array lengths used in a short run + private static final int[] SHORT_RUN_LENGTHS = { 1, 2, 3, 21, 55, 1000, 10000 }; + + // Random initial values used in a long run (default) + private static final long[] LONG_RUN_RANDOMS = {666, 0xC0FFEE, 999}; + + // Random initial values used in a short run + private static final long[] SHORT_RUN_RANDOMS = {666}; public static void main(String[] args) { - boolean shortRun = false; - if (args.length > 0 && args[0].equals("-shortrun")) - shortRun = true; + boolean shortRun = args.length > 0 && args[0].equals("-shortrun"); + long start = System.currentTimeMillis(); - long start = System.nanoTime(); + if (shortRun) { + testAndCheck(SHORT_RUN_LENGTHS, SHORT_RUN_RANDOMS); + } else { + testAndCheck(LONG_RUN_LENGTHS, LONG_RUN_RANDOMS); + } + long end = System.currentTimeMillis(); - testAndCheck((shortRun) ? SHORT_RUN : LONG_RUN); - - long end = System.nanoTime(); - - out.println(); - out.format("PASS in %ds%n", Math.round((end - start) / 1e9)); + out.format("PASS in %d sec.\n", Math.round((end - start) / 1E3)); } - static void testAndCheck(int[] lengths) { - for (int len : lengths) { - out.println(); - ArrayBuilder.reset(); - int[] golden = new int[len]; + private static void testAndCheck(int[] lengths, long[] randoms) { + for (long random : randoms) { + reset(random); - for (int m = 1; m < 2 * len; m *= 2) { - for (ArrayBuilder builder : ArrayBuilder.values()) { - builder.build(golden, m); - int[] test = golden.clone(); + for (int len : lengths) { + testAndCheckWithCheckSum(len, random); + } + reset(random); - for (Converter converter : Converter.values()) { - out.println("Test: " + converter + " " + builder + - "len = " + len + ", m = " + m); - Object convertedGolden = converter.convert(golden); - Object convertedTest = converter.convert(test); - sort(convertedTest); - checkWithCheckSum(convertedTest, convertedGolden); - } - } + for (int len : lengths) { + testAndCheckWithScrambling(len, random); + } + reset(random); + + for (int len : lengths) { + testAndCheckFloat(len, random); + } + reset(random); + + for (int len : lengths) { + testAndCheckDouble(len, random); + } + reset(random); + + for (int len : lengths) { + testAndCheckRange(len, random); + } + reset(random); + + for (int len : lengths) { + testAndCheckSubArray(len, random); } } } - static enum Converter { + private static void testAndCheckSubArray(int len, long random) { + int[] golden = new int[len]; + + for (int m = 1; m < len / 2; m *= 2) { + int fromIndex = m; + int toIndex = len - m; + + prepareSubArray(golden, fromIndex, toIndex, m); + int[] test = golden.clone(); + + for (TypeConverter converter : TypeConverter.values()) { + out.println("Test #6: " + converter + + " len = " + len + ", m = " + m); + Object convertedGolden = converter.convert(golden); + Object convertedTest = converter.convert(test); + + // outArr(test); + sortSubArray(convertedTest, fromIndex, toIndex); + // outArr(test); + checkSubArray(convertedTest, fromIndex, toIndex, m); + } + } + out.println(); + } + + private static void testAndCheckRange(int len, long random) { + int[] golden = new int[len]; + + for (int m = 1; m < 2 * len; m *= 2) { + for (int i = 1; i <= len; i++) { + golden[i - 1] = i % m + m % i; + } + for (TypeConverter converter : TypeConverter.values()) { + out.println("Test #5: " + converter + + ", len = " + len + ", m = " + m); + Object convertedGolden = converter.convert(golden); + sortRange(convertedGolden, m); + sortEmpty(convertedGolden); + } + } + out.println(); + } + + private static void testAndCheckWithCheckSum(int len, long random) { + int[] golden = new int[len]; + + for (int m = 1; m < 2 * len; m *= 2) { + for (UnsortedBuilder builder : UnsortedBuilder.values()) { + builder.build(golden, m); + int[] test = golden.clone(); + + for (TypeConverter converter : TypeConverter.values()) { + out.println("Test #1: " + converter + " " + builder + + "random = " + random + ", len = " + len + + ", m = " + m); + Object convertedGolden = converter.convert(golden); + Object convertedTest = converter.convert(test); + sort(convertedTest); + checkWithCheckSum(convertedTest, convertedGolden); + } + } + } + out.println(); + } + + private static void testAndCheckWithScrambling(int len, long random) { + int[] golden = new int[len]; + + for (int m = 1; m <= 7; m++) { + if (m > len) { + break; + } + for (SortedBuilder builder : SortedBuilder.values()) { + builder.build(golden, m); + int[] test = golden.clone(); + scramble(test); + + for (TypeConverter converter : TypeConverter.values()) { + out.println("Test #2: " + converter + " " + builder + + "random = " + random + ", len = " + len + + ", m = " + m); + Object convertedGolden = converter.convert(golden); + Object convertedTest = converter.convert(test); + sort(convertedTest); + compare(convertedTest, convertedGolden); + } + } + } + out.println(); + } + + private static void testAndCheckFloat(int len, long random) { + float[] golden = new float[len]; + final int MAX = 10; + boolean newLine = false; + + for (int a = 0; a <= MAX; a++) { + for (int g = 0; g <= MAX; g++) { + for (int z = 0; z <= MAX; z++) { + for (int n = 0; n <= MAX; n++) { + for (int p = 0; p <= MAX; p++) { + if (a + g + z + n + p > len) { + continue; + } + if (a + g + z + n + p < len) { + continue; + } + for (FloatBuilder builder : FloatBuilder.values()) { + out.println("Test #3: random = " + random + + ", len = " + len + ", a = " + a + ", g = " + g + + ", z = " + z + ", n = " + n + ", p = " + p); + builder.build(golden, a, g, z, n, p); + float[] test = golden.clone(); + scramble(test); + // outArr(test); + sort(test); + // outArr(test); + compare(test, golden, a, n, g); + } + newLine = true; + } + } + } + } + } + if (newLine) { + out.println(); + } + } + + private static void testAndCheckDouble(int len, long random) { + double[] golden = new double[len]; + final int MAX = 10; + boolean newLine = false; + + for (int a = 0; a <= MAX; a++) { + for (int g = 0; g <= MAX; g++) { + for (int z = 0; z <= MAX; z++) { + for (int n = 0; n <= MAX; n++) { + for (int p = 0; p <= MAX; p++) { + if (a + g + z + n + p > len) { + continue; + } + if (a + g + z + n + p < len) { + continue; + } + for (DoubleBuilder builder : DoubleBuilder.values()) { + out.println("Test #4: random = " + random + + ", len = " + len + ", a = " + a + ", g = " + g + + ", z = " + z + ", n = " + n + ", p = " + p); + builder.build(golden, a, g, z, n, p); + double[] test = golden.clone(); + scramble(test); + // outArr(test); + sort(test); + // outArr(test); + compare(test, golden, a, n, g); + } + newLine = true; + } + } + } + } + } + if (newLine) { + out.println(); + } + } + + private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + a[i] = 0xBABA; + } + + for (int i = fromIndex; i < toIndex; i++) { + a[i] = -i + m; + } + + for (int i = toIndex; i < a.length; i++) { + a[i] = 0xDEDA; + } + } + + private static void scramble(int[] a) { + int length = a.length; + + for (int i = 0; i < length * 7; i++) { + swap(a, ourRandom.nextInt(length), ourRandom.nextInt(length)); + } + } + + private static void scramble(float[] a) { + int length = a.length; + + for (int i = 0; i < length * 7; i++) { + swap(a, ourRandom.nextInt(length), ourRandom.nextInt(length)); + } + } + + private static void scramble(double[] a) { + int length = a.length; + + for (int i = 0; i < length * 7; i++) { + swap(a, ourRandom.nextInt(length), ourRandom.nextInt(length)); + } + } + + private static void swap(int[] a, int i, int j) { + int t = a[i]; + a[i] = a[j]; + a[j] = t; + } + + private static void swap(float[] a, int i, int j) { + float t = a[i]; + a[i] = a[j]; + a[j] = t; + } + + private static void swap(double[] a, int i, int j) { + double t = a[i]; + a[i] = a[j]; + a[j] = t; + } + + private static enum TypeConverter { INT { Object convert(int[] a) { - return a; + return a.clone(); } }, LONG { @@ -95,7 +339,7 @@ public class Sorting { long[] b = new long[a.length]; for (int i = 0; i < a.length; i++) { - b[i] = (int) a[i]; + b[i] = (long) a[i]; } return b; } @@ -163,7 +407,161 @@ public class Sorting { } } - static enum ArrayBuilder { + private static enum FloatBuilder { + SIMPLE { + void build(float[] x, int a, int g, int z, int n, int p) { + int fromIndex = 0; + float negativeValue = -ourRandom.nextFloat(); + float positiveValue = ourRandom.nextFloat(); + + writeValue(x, negativeValue, fromIndex, n); + fromIndex += n; + + writeValue(x, -0.0f, fromIndex, g); + fromIndex += g; + + writeValue(x, 0.0f, fromIndex, z); + fromIndex += z; + + writeValue(x, positiveValue, fromIndex, p); + fromIndex += p; + + writeValue(x, Float.NaN, fromIndex, a); + } + }; + + abstract void build(float[] x, int a, int g, int z, int n, int p); + } + + private static enum DoubleBuilder { + SIMPLE { + void build(double[] x, int a, int g, int z, int n, int p) { + int fromIndex = 0; + double negativeValue = -ourRandom.nextFloat(); + double positiveValue = ourRandom.nextFloat(); + + writeValue(x, negativeValue, fromIndex, n); + fromIndex += n; + + writeValue(x, -0.0d, fromIndex, g); + fromIndex += g; + + writeValue(x, 0.0d, fromIndex, z); + fromIndex += z; + + writeValue(x, positiveValue, fromIndex, p); + fromIndex += p; + + writeValue(x, Double.NaN, fromIndex, a); + } + }; + + abstract void build(double[] x, int a, int g, int z, int n, int p); + } + + private static void writeValue(float[] a, float value, int fromIndex, int count) { + for (int i = fromIndex; i < fromIndex + count; i++) { + a[i] = value; + } + } + + private static void compare(float[] a, float[] b, int numNaN, int numNeg, int numNegZero) { + for (int i = a.length - numNaN; i < a.length; i++) { + if (a[i] == a[i]) { + failed("On position " + i + " must be NaN instead of " + a[i]); + } + } + final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f); + + for (int i = numNeg; i < numNeg + numNegZero; i++) { + if (NEGATIVE_ZERO != Float.floatToIntBits(a[i])) { + failed("On position " + i + " must be -0.0f instead of " + a[i]); + } + } + for (int i = 0; i < a.length - numNaN; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void writeValue(double[] a, double value, int fromIndex, int count) { + for (int i = fromIndex; i < fromIndex + count; i++) { + a[i] = value; + } + } + + private static void compare(double[] a, double[] b, int numNaN, int numNeg, int numNegZero) { + for (int i = a.length - numNaN; i < a.length; i++) { + if (a[i] == a[i]) { + failed("On position " + i + " must be NaN instead of " + a[i]); + } + } + final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d); + + for (int i = numNeg; i < numNeg + numNegZero; i++) { + if (NEGATIVE_ZERO != Double.doubleToLongBits(a[i])) { + failed("On position " + i + " must be -0.0d instead of " + a[i]); + } + } + for (int i = 0; i < a.length - numNaN; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static enum SortedBuilder { + REPEATED { + void build(int[] a, int m) { + int period = a.length / m; + int i = 0; + int k = 0; + + while (true) { + for (int t = 1; t <= period; t++) { + if (i >= a.length) { + return; + } + a[i++] = k; + } + if (i >= a.length) { + return; + } + k++; + } + } + }, + + ORGAN_PIPES { + void build(int[] a, int m) { + int i = 0; + int k = m; + + while (true) { + for (int t = 1; t <= m; t++) { + if (i >= a.length) { + return; + } + a[i++] = k; + } + } + } + }; + + abstract void build(int[] a, int m); + + @Override public String toString() { + String name = name(); + + for (int i = name.length(); i < 12; i++) { + name += " "; + } + return name; + } + } + + private static enum UnsortedBuilder { RANDOM { void build(int[] a, int m) { for (int i = 0; i < a.length; i++) { @@ -268,41 +666,53 @@ public class Sorting { abstract void build(int[] a, int m); - static void reset() { - ourRandom = new Random(666); - ourFirst = 0; - ourSecond = 0; - } - @Override public String toString() { String name = name(); + for (int i = name.length(); i < 12; i++) { name += " "; } return name; } - - private static int ourFirst; - private static int ourSecond; - private static Random ourRandom = new Random(666); } - static void checkWithCheckSum(Object test, Object golden) { + private static void compare(Object test, Object golden) { + if (test instanceof int[]) { + compare((int[]) test, (int[]) golden); + } else if (test instanceof long[]) { + compare((long[]) test, (long[]) golden); + } else if (test instanceof short[]) { + compare((short[]) test, (short[]) golden); + } else if (test instanceof byte[]) { + compare((byte[]) test, (byte[]) golden); + } else if (test instanceof char[]) { + compare((char[]) test, (char[]) golden); + } else if (test instanceof float[]) { + compare((float[]) test, (float[]) golden); + } else if (test instanceof double[]) { + compare((double[]) test, (double[]) golden); + } else { + failed("Unknow type of array: " + test + " of class " + + test.getClass().getName()); + } + } + + private static void checkWithCheckSum(Object test, Object golden) { checkSorted(test); checkCheckSum(test, golden); } - static void failed(String message) { - err.format("***FAILED: %s%%n", message); + private static void failed(String message) { + err.format("\n*** FAILED: %s\n\n", message); throw new RuntimeException("Test failed - see log file for details"); } - static void failed(int index, String value1, String value2) { + private static void failed(int index, String value1, String value2) { failed("Array is not sorted at " + index + "-th position: " + value1 + " and " + value2); } - static void checkSorted(Object object) { + private static void checkSorted(Object object) { if (object instanceof int[]) { checkSorted((int[]) object); } else if (object instanceof long[]) { @@ -323,7 +733,63 @@ public class Sorting { } } - static void checkSorted(int[] a) { + private static void compare(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void compare(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void compare(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void compare(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void compare(char[] a, char[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void compare(float[] a, float[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void compare(double[] a, double[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void checkSorted(int[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -331,7 +797,7 @@ public class Sorting { } } - static void checkSorted(long[] a) { + private static void checkSorted(long[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -339,7 +805,7 @@ public class Sorting { } } - static void checkSorted(short[] a) { + private static void checkSorted(short[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -347,7 +813,7 @@ public class Sorting { } } - static void checkSorted(byte[] a) { + private static void checkSorted(byte[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -355,7 +821,7 @@ public class Sorting { } } - static void checkSorted(char[] a) { + private static void checkSorted(char[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -363,7 +829,7 @@ public class Sorting { } } - static void checkSorted(float[] a) { + private static void checkSorted(float[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -371,7 +837,7 @@ public class Sorting { } } - static void checkSorted(double[] a) { + private static void checkSorted(double[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -379,13 +845,13 @@ public class Sorting { } } - static void checkCheckSum(Object test, Object golden) { + private static void checkCheckSum(Object test, Object golden) { if (checkSum(test) != checkSum(golden)) { failed("Original and sorted arrays seems not identical"); } } - static int checkSum(Object object) { + private static int checkSum(Object object) { if (object instanceof int[]) { return checkSum((int[]) object); } else if (object instanceof long[]) { @@ -407,70 +873,70 @@ public class Sorting { } } - static int checkSum(int[] a) { - int checkSum = 0; + private static int checkSum(int[] a) { + int checkXorSum = 0; for (int e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return checkSum; + return checkXorSum; } - static int checkSum(long[] a) { - long checkSum = 0; + private static int checkSum(long[] a) { + long checkXorSum = 0; for (long e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return (int) checkSum; + return (int) checkXorSum; } - static int checkSum(short[] a) { - short checkSum = 0; + private static int checkSum(short[] a) { + short checkXorSum = 0; for (short e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return (int) checkSum; + return (int) checkXorSum; } - static int checkSum(byte[] a) { - byte checkSum = 0; + private static int checkSum(byte[] a) { + byte checkXorSum = 0; for (byte e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return (int) checkSum; + return (int) checkXorSum; } - static int checkSum(char[] a) { - char checkSum = 0; + private static int checkSum(char[] a) { + char checkXorSum = 0; for (char e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return (int) checkSum; + return (int) checkXorSum; } - static int checkSum(float[] a) { - int checkSum = 0; + private static int checkSum(float[] a) { + int checkXorSum = 0; for (float e : a) { - checkSum ^= (int) e; // xor + checkXorSum ^= (int) e; } - return checkSum; + return checkXorSum; } - static int checkSum(double[] a) { - int checkSum = 0; + private static int checkSum(double[] a) { + int checkXorSum = 0; for (double e : a) { - checkSum ^= (int) e; // xor + checkXorSum ^= (int) e; } - return checkSum; + return checkXorSum; } - static void sort(Object object) { + private static void sort(Object object) { if (object instanceof int[]) { Arrays.sort((int[]) object); } else if (object instanceof long[]) { @@ -490,4 +956,485 @@ public class Sorting { object.getClass().getName()); } } + + private static void sortSubArray(Object object, int fromIndex, int toIndex) { + if (object instanceof int[]) { + Arrays.sort((int[]) object, fromIndex, toIndex); + } else if (object instanceof long[]) { + Arrays.sort((long[]) object, fromIndex, toIndex); + } else if (object instanceof short[]) { + Arrays.sort((short[]) object, fromIndex, toIndex); + } else if (object instanceof byte[]) { + Arrays.sort((byte[]) object, fromIndex, toIndex); + } else if (object instanceof char[]) { + Arrays.sort((char[]) object, fromIndex, toIndex); + } else if (object instanceof float[]) { + Arrays.sort((float[]) object, fromIndex, toIndex); + } else if (object instanceof double[]) { + Arrays.sort((double[]) object, fromIndex, toIndex); + } else { + failed("Unknow type of array: " + object + " of class " + + object.getClass().getName()); + } + } + + private static void checkSubArray(Object object, int fromIndex, int toIndex, int m) { + if (object instanceof int[]) { + checkSubArray((int[]) object, fromIndex, toIndex, m); + } else if (object instanceof long[]) { + checkSubArray((long[]) object, fromIndex, toIndex, m); + } else if (object instanceof short[]) { + checkSubArray((short[]) object, fromIndex, toIndex, m); + } else if (object instanceof byte[]) { + checkSubArray((byte[]) object, fromIndex, toIndex, m); + } else if (object instanceof char[]) { + checkSubArray((char[]) object, fromIndex, toIndex, m); + } else if (object instanceof float[]) { + checkSubArray((float[]) object, fromIndex, toIndex, m); + } else if (object instanceof double[]) { + checkSubArray((double[]) object, fromIndex, toIndex, m); + } else { + failed("Unknow type of array: " + object + " of class " + + object.getClass().getName()); + } + } + + private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (byte) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (byte) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (long) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (long) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (char) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (char) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (short) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (short) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (float) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (float) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (double) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (double) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void sortRange(Object object, int m) { + if (object instanceof int[]) { + sortRange((int[]) object, m); + } else if (object instanceof long[]) { + sortRange((long[]) object, m); + } else if (object instanceof short[]) { + sortRange((short[]) object, m); + } else if (object instanceof byte[]) { + sortRange((byte[]) object, m); + } else if (object instanceof char[]) { + sortRange((char[]) object, m); + } else if (object instanceof float[]) { + sortRange((float[]) object, m); + } else if (object instanceof double[]) { + sortRange((double[]) object, m); + } else { + failed("Unknow type of array: " + object + " of class " + + object.getClass().getName()); + } + } + + private static void sortEmpty(Object object) { + if (object instanceof int[]) { + Arrays.sort(new int [] {}); + } else if (object instanceof long[]) { + Arrays.sort(new long [] {}); + } else if (object instanceof short[]) { + Arrays.sort(new short [] {}); + } else if (object instanceof byte[]) { + Arrays.sort(new byte [] {}); + } else if (object instanceof char[]) { + Arrays.sort(new char [] {}); + } else if (object instanceof float[]) { + Arrays.sort(new float [] {}); + } else if (object instanceof double[]) { + Arrays.sort(new double [] {}); + } else { + failed("Unknow type of array: " + object + " of class " + + object.getClass().getName()); + } + } + + private static void sortRange(int[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(long[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(byte[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(short[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(char[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(float[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(double[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void prepareRandom(int[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = ourRandom.nextInt(); + } + } + + private static void reset(long seed) { + ourRandom = new Random(seed); + ourFirst = 0; + ourSecond = 0; + } + + private static void outArr(int[] a) { + for (int i = 0; i < a.length; i++) { + out.print(a[i] + " "); + } + out.println(); + out.println(); + } + + private static void outArr(float[] a) { + for (int i = 0; i < a.length; i++) { + out.print(a[i] + " "); + } + out.println(); + out.println(); + } + + private static void outArr(double[] a) { + for (int i = 0; i < a.length; i++) { + out.print(a[i] + " "); + } + out.println(); + out.println(); + } + + private static int ourFirst; + private static int ourSecond; + private static Random ourRandom; } diff --git a/jdk/test/java/util/Collection/BiggernYours.java b/jdk/test/java/util/Collection/BiggernYours.java index a9cb59c007d..c059f9abe75 100644 --- a/jdk/test/java/util/Collection/BiggernYours.java +++ b/jdk/test/java/util/Collection/BiggernYours.java @@ -178,10 +178,10 @@ public class BiggernYours { new ConcurrentLinkedQueue() { public int size() {return randomize(super.size());}}); -// testCollections( -// new LinkedTransferQueue(), -// new LinkedTransferQueue() { -// public int size() {return randomize(super.size());}}); + testCollections( + new LinkedTransferQueue(), + new LinkedTransferQueue() { + public int size() {return randomize(super.size());}}); testCollections( new LinkedBlockingQueue(), diff --git a/jdk/test/java/util/Collection/IteratorAtEnd.java b/jdk/test/java/util/Collection/IteratorAtEnd.java index ff8ae97c563..b759d7edf86 100644 --- a/jdk/test/java/util/Collection/IteratorAtEnd.java +++ b/jdk/test/java/util/Collection/IteratorAtEnd.java @@ -49,7 +49,7 @@ public class IteratorAtEnd { testCollection(new LinkedBlockingQueue()); testCollection(new ArrayBlockingQueue(100)); testCollection(new ConcurrentLinkedQueue()); -// testCollection(new LinkedTransferQueue()); + testCollection(new LinkedTransferQueue()); testMap(new HashMap()); testMap(new Hashtable()); diff --git a/jdk/test/java/util/Collection/MOAT.java b/jdk/test/java/util/Collection/MOAT.java index 0b4fc6a3f2c..6c86c947f6c 100644 --- a/jdk/test/java/util/Collection/MOAT.java +++ b/jdk/test/java/util/Collection/MOAT.java @@ -76,7 +76,7 @@ public class MOAT { testCollection(new LinkedBlockingQueue(20)); testCollection(new LinkedBlockingDeque(20)); testCollection(new ConcurrentLinkedQueue()); -// testCollection(new LinkedTransferQueue()); + testCollection(new LinkedTransferQueue()); testCollection(new ConcurrentSkipListSet()); testCollection(Arrays.asList(new Integer(42))); testCollection(Arrays.asList(1,2,3)); @@ -421,8 +421,11 @@ public class MOAT { private static void testQueue(Queue q) { q.clear(); - for (int i = 0; i < 5; i++) + for (int i = 0; i < 5; i++) { + testQueueAddRemove(q, null); + testQueueAddRemove(q, 537); q.add(i); + } equal(q.size(), 5); checkFunctionalInvariants(q); q.poll(); @@ -435,6 +438,216 @@ public class MOAT { } } + private static void testQueueAddRemove(final Queue q, + final Integer e) { + final List originalContents = new ArrayList(q); + final boolean isEmpty = q.isEmpty(); + final boolean isList = (q instanceof List); + final List asList = isList ? (List) q : null; + check(!q.contains(e)); + try { + q.add(e); + } catch (NullPointerException npe) { + check(e == null); + return; // Null elements not supported + } + check(q.contains(e)); + check(q.remove(e)); + check(!q.contains(e)); + equal(new ArrayList(q), originalContents); + + if (q instanceof Deque) { + final Deque deq = (Deque) q; + final List singleton = Collections.singletonList(e); + + // insert, query, remove element at head + if (isEmpty) { + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.getFirst(); }}, + new Fun(){void f(){ deq.element(); }}, + new Fun(){void f(){ deq.iterator().next(); }}); + check(deq.peekFirst() == null); + check(deq.peek() == null); + } else { + check(deq.getFirst() != e); + check(deq.element() != e); + check(deq.iterator().next() != e); + check(deq.peekFirst() != e); + check(deq.peek() != e); + } + check(!deq.contains(e)); + check(!deq.removeFirstOccurrence(e)); + check(!deq.removeLastOccurrence(e)); + if (isList) { + check(asList.indexOf(e) == -1); + check(asList.lastIndexOf(e) == -1); + } + switch (rnd.nextInt(isList ? 4 : 3)) { + case 0: deq.addFirst(e); break; + case 1: check(deq.offerFirst(e)); break; + case 2: deq.push(e); break; + case 3: asList.add(0, e); break; + default: throw new AssertionError(); + } + check(deq.peekFirst() == e); + check(deq.getFirst() == e); + check(deq.element() == e); + check(deq.peek() == e); + check(deq.iterator().next() == e); + check(deq.contains(e)); + if (isList) { + check(asList.get(0) == e); + check(asList.indexOf(e) == 0); + check(asList.lastIndexOf(e) == 0); + check(asList.subList(0, 1).equals(singleton)); + } + switch (rnd.nextInt(isList ? 11 : 9)) { + case 0: check(deq.pollFirst() == e); break; + case 1: check(deq.removeFirst() == e); break; + case 2: check(deq.remove() == e); break; + case 3: check(deq.pop() == e); break; + case 4: check(deq.removeFirstOccurrence(e)); break; + case 5: check(deq.removeLastOccurrence(e)); break; + case 6: check(deq.remove(e)); break; + case 7: check(deq.removeAll(singleton)); break; + case 8: Iterator it = deq.iterator(); it.next(); it.remove(); break; + case 9: asList.remove(0); break; + case 10: asList.subList(0, 1).clear(); break; + default: throw new AssertionError(); + } + if (isEmpty) { + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.getFirst(); }}, + new Fun(){void f(){ deq.element(); }}, + new Fun(){void f(){ deq.iterator().next(); }}); + check(deq.peekFirst() == null); + check(deq.peek() == null); + } else { + check(deq.getFirst() != e); + check(deq.element() != e); + check(deq.iterator().next() != e); + check(deq.peekFirst() != e); + check(deq.peek() != e); + } + check(!deq.contains(e)); + check(!deq.removeFirstOccurrence(e)); + check(!deq.removeLastOccurrence(e)); + if (isList) { + check(isEmpty || asList.get(0) != e); + check(asList.indexOf(e) == -1); + check(asList.lastIndexOf(e) == -1); + } + equal(new ArrayList(deq), originalContents); + + // insert, query, remove element at tail + if (isEmpty) { + check(deq.peekLast() == null); + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.getLast(); }}); + } else { + check(deq.peekLast() != e); + check(deq.getLast() != e); + } + switch (rnd.nextInt(isList ? 6 : 4)) { + case 0: deq.addLast(e); break; + case 1: check(deq.offerLast(e)); break; + case 2: check(deq.add(e)); break; + case 3: deq.addAll(singleton); break; + case 4: asList.addAll(deq.size(), singleton); break; + case 5: asList.add(deq.size(), e); break; + default: throw new AssertionError(); + } + check(deq.peekLast() == e); + check(deq.getLast() == e); + check(deq.contains(e)); + if (isList) { + ListIterator it = asList.listIterator(asList.size()); + check(it.previous() == e); + check(asList.get(asList.size() - 1) == e); + check(asList.indexOf(e) == asList.size() - 1); + check(asList.lastIndexOf(e) == asList.size() - 1); + int size = asList.size(); + check(asList.subList(size - 1, size).equals(singleton)); + } + switch (rnd.nextInt(isList ? 8 : 6)) { + case 0: check(deq.pollLast() == e); break; + case 1: check(deq.removeLast() == e); break; + case 2: check(deq.removeFirstOccurrence(e)); break; + case 3: check(deq.removeLastOccurrence(e)); break; + case 4: check(deq.remove(e)); break; + case 5: check(deq.removeAll(singleton)); break; + case 6: asList.remove(asList.size() - 1); break; + case 7: + ListIterator it = asList.listIterator(asList.size()); + it.previous(); + it.remove(); + break; + default: throw new AssertionError(); + } + if (isEmpty) { + check(deq.peekLast() == null); + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.getLast(); }}); + } else { + check(deq.peekLast() != e); + check(deq.getLast() != e); + } + check(!deq.contains(e)); + equal(new ArrayList(deq), originalContents); + + // Test operations on empty deque + switch (rnd.nextInt(isList ? 4 : 2)) { + case 0: deq.clear(); break; + case 1: + Iterator it = deq.iterator(); + while (it.hasNext()) { + it.next(); + it.remove(); + } + break; + case 2: asList.subList(0, asList.size()).clear(); break; + case 3: + ListIterator lit = asList.listIterator(asList.size()); + while (lit.hasPrevious()) { + lit.previous(); + lit.remove(); + } + break; + default: throw new AssertionError(); + } + testEmptyCollection(deq); + check(!deq.iterator().hasNext()); + if (isList) { + check(!asList.listIterator().hasPrevious()); + THROWS(NoSuchElementException.class, + new Fun(){void f(){ asList.listIterator().previous(); }}); + } + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.iterator().next(); }}, + new Fun(){void f(){ deq.element(); }}, + new Fun(){void f(){ deq.getFirst(); }}, + new Fun(){void f(){ deq.getLast(); }}, + new Fun(){void f(){ deq.pop(); }}, + new Fun(){void f(){ deq.remove(); }}, + new Fun(){void f(){ deq.removeFirst(); }}, + new Fun(){void f(){ deq.removeLast(); }}); + + check(deq.poll() == null); + check(deq.pollFirst() == null); + check(deq.pollLast() == null); + check(deq.peek() == null); + check(deq.peekFirst() == null); + check(deq.peekLast() == null); + check(!deq.removeFirstOccurrence(e)); + check(!deq.removeLastOccurrence(e)); + + check(deq.addAll(originalContents) == !isEmpty); + equal(new ArrayList(deq), originalContents); + check(!deq.addAll(Collections.emptyList())); + equal(new ArrayList(deq), originalContents); + } + } + private static void testQueueIteratorRemove(Queue q) { System.err.printf("testQueueIteratorRemove %s%n", q.getClass().getSimpleName()); diff --git a/jdk/test/java/util/Collections/CheckedNull.java b/jdk/test/java/util/Collections/CheckedNull.java index 6bb19e7bf62..ddd0205c18f 100644 --- a/jdk/test/java/util/Collections/CheckedNull.java +++ b/jdk/test/java/util/Collections/CheckedNull.java @@ -52,7 +52,7 @@ public class CheckedNull { testMap(Collections.checkedMap( new HashMap(), - String.class, String.class));; + String.class, String.class)); } ClassCastException cce(F f) { diff --git a/jdk/test/java/util/Collections/RacingCollections.java b/jdk/test/java/util/Collections/RacingCollections.java index 32e41cf8b14..23dc8976745 100644 --- a/jdk/test/java/util/Collections/RacingCollections.java +++ b/jdk/test/java/util/Collections/RacingCollections.java @@ -234,7 +234,7 @@ public class RacingCollections { List> list = new ArrayList>(newConcurrentDeques()); list.add(new LinkedBlockingQueue(10)); -// list.add(new LinkedTransferQueue()); + list.add(new LinkedTransferQueue()); return list; } diff --git a/jdk/test/java/util/PriorityQueue/RemoveContains.java b/jdk/test/java/util/PriorityQueue/RemoveContains.java index 85c9d214c7f..6e52709f1cf 100644 --- a/jdk/test/java/util/PriorityQueue/RemoveContains.java +++ b/jdk/test/java/util/PriorityQueue/RemoveContains.java @@ -69,7 +69,7 @@ public class RemoveContains { test(new ArrayBlockingQueue(10)); test(new LinkedBlockingQueue(10)); test(new LinkedBlockingDeque(10)); -// test(new LinkedTransferQueue()); + test(new LinkedTransferQueue()); test(new ArrayDeque(10)); System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); diff --git a/jdk/test/java/util/concurrent/BlockingQueue/CancelledProducerConsumerLoops.java b/jdk/test/java/util/concurrent/BlockingQueue/CancelledProducerConsumerLoops.java index 210f43c0d9d..98ac5d744e2 100644 --- a/jdk/test/java/util/concurrent/BlockingQueue/CancelledProducerConsumerLoops.java +++ b/jdk/test/java/util/concurrent/BlockingQueue/CancelledProducerConsumerLoops.java @@ -119,12 +119,36 @@ public class CancelledProducerConsumerLoops { } } + static final class LTQasSQ extends LinkedTransferQueue { + LTQasSQ() { super(); } + public void put(T x) { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + private final static long serialVersionUID = 42; + } + + static final class HalfSyncLTQ extends LinkedTransferQueue { + HalfSyncLTQ() { super(); } + public void put(T x) { + if (ThreadLocalRandom.current().nextBoolean()) + super.put(x); + else { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + } + private final static long serialVersionUID = 42; + } + static void oneTest(int pairs, int iters) throws Exception { oneRun(new ArrayBlockingQueue(CAPACITY), pairs, iters); oneRun(new LinkedBlockingQueue(CAPACITY), pairs, iters); oneRun(new LinkedBlockingDeque(CAPACITY), pairs, iters); -// oneRun(new LinkedTransferQueue(), pairs, iters); + oneRun(new LinkedTransferQueue(), pairs, iters); + oneRun(new LTQasSQ(), pairs, iters); + oneRun(new HalfSyncLTQ(), pairs, iters); oneRun(new SynchronousQueue(), pairs, iters / 8); /* PriorityBlockingQueue is unbounded diff --git a/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java b/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java index a4c27872f34..e7dd155916a 100644 --- a/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java +++ b/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java @@ -37,7 +37,7 @@ public class LastElement { testQueue(new LinkedBlockingDeque()); testQueue(new ArrayBlockingQueue(10, true)); testQueue(new ArrayBlockingQueue(10, false)); -// testQueue(new LinkedTransferQueue()); + testQueue(new LinkedTransferQueue()); System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new Exception("Some tests failed"); diff --git a/jdk/test/java/util/concurrent/BlockingQueue/MultipleProducersSingleConsumerLoops.java b/jdk/test/java/util/concurrent/BlockingQueue/MultipleProducersSingleConsumerLoops.java index 0e0fd82430e..8b7db5a945d 100644 --- a/jdk/test/java/util/concurrent/BlockingQueue/MultipleProducersSingleConsumerLoops.java +++ b/jdk/test/java/util/concurrent/BlockingQueue/MultipleProducersSingleConsumerLoops.java @@ -87,11 +87,35 @@ public class MultipleProducersSingleConsumerLoops { throw new Error(); } + static final class LTQasSQ extends LinkedTransferQueue { + LTQasSQ() { super(); } + public void put(T x) { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + private final static long serialVersionUID = 42; + } + + static final class HalfSyncLTQ extends LinkedTransferQueue { + HalfSyncLTQ() { super(); } + public void put(T x) { + if (ThreadLocalRandom.current().nextBoolean()) + super.put(x); + else { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + } + private final static long serialVersionUID = 42; + } + static void oneTest(int producers, int iters) throws Exception { oneRun(new ArrayBlockingQueue(CAPACITY), producers, iters); oneRun(new LinkedBlockingQueue(CAPACITY), producers, iters); oneRun(new LinkedBlockingDeque(CAPACITY), producers, iters); -// oneRun(new LinkedTransferQueue(), producers, iters); + oneRun(new LinkedTransferQueue(), producers, iters); + oneRun(new LTQasSQ(), producers, iters); + oneRun(new HalfSyncLTQ(), producers, iters); // Don't run PBQ since can legitimately run out of memory // if (print) diff --git a/jdk/test/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java b/jdk/test/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java index 1721b916dce..94d3e9a3bba 100644 --- a/jdk/test/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java +++ b/jdk/test/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java @@ -63,12 +63,11 @@ public class OfferDrainToLoops { test(new LinkedBlockingDeque()); test(new LinkedBlockingDeque(2000)); test(new ArrayBlockingQueue(2000)); -// test(new LinkedTransferQueue()); + test(new LinkedTransferQueue()); } Random getRandom() { - return new Random(); - // return ThreadLocalRandom.current(); + return ThreadLocalRandom.current(); } void test(final BlockingQueue q) throws Throwable { diff --git a/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java b/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java index 9e47162c6c2..df9049d737c 100644 --- a/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java +++ b/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java @@ -46,7 +46,7 @@ public class PollMemoryLeak { public static void main(String[] args) throws InterruptedException { final BlockingQueue[] qs = { new LinkedBlockingQueue(10), -// new LinkedTransferQueue(), + new LinkedTransferQueue(), new ArrayBlockingQueue(10), new SynchronousQueue(), new SynchronousQueue(true), diff --git a/jdk/test/java/util/concurrent/BlockingQueue/ProducerConsumerLoops.java b/jdk/test/java/util/concurrent/BlockingQueue/ProducerConsumerLoops.java index b40c49f3688..761990d3a92 100644 --- a/jdk/test/java/util/concurrent/BlockingQueue/ProducerConsumerLoops.java +++ b/jdk/test/java/util/concurrent/BlockingQueue/ProducerConsumerLoops.java @@ -87,11 +87,35 @@ public class ProducerConsumerLoops { throw new Error(); } + static final class LTQasSQ extends LinkedTransferQueue { + LTQasSQ() { super(); } + public void put(T x) { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + private final static long serialVersionUID = 42; + } + + static final class HalfSyncLTQ extends LinkedTransferQueue { + HalfSyncLTQ() { super(); } + public void put(T x) { + if (ThreadLocalRandom.current().nextBoolean()) + super.put(x); + else { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + } + private final static long serialVersionUID = 42; + } + static void oneTest(int pairs, int iters) throws Exception { oneRun(new ArrayBlockingQueue(CAPACITY), pairs, iters); oneRun(new LinkedBlockingQueue(CAPACITY), pairs, iters); oneRun(new LinkedBlockingDeque(CAPACITY), pairs, iters); -// oneRun(new LinkedTransferQueue(), pairs, iters); + oneRun(new LinkedTransferQueue(), pairs, iters); + oneRun(new LTQasSQ(), pairs, iters); + oneRun(new HalfSyncLTQ(), pairs, iters); oneRun(new PriorityBlockingQueue(), pairs, iters); oneRun(new SynchronousQueue(), pairs, iters); diff --git a/jdk/test/java/util/concurrent/BlockingQueue/SingleProducerMultipleConsumerLoops.java b/jdk/test/java/util/concurrent/BlockingQueue/SingleProducerMultipleConsumerLoops.java index 8c718b97602..c99a664b787 100644 --- a/jdk/test/java/util/concurrent/BlockingQueue/SingleProducerMultipleConsumerLoops.java +++ b/jdk/test/java/util/concurrent/BlockingQueue/SingleProducerMultipleConsumerLoops.java @@ -73,11 +73,35 @@ public class SingleProducerMultipleConsumerLoops { throw new Error(); } + static final class LTQasSQ extends LinkedTransferQueue { + LTQasSQ() { super(); } + public void put(T x) { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + private final static long serialVersionUID = 42; + } + + static final class HalfSyncLTQ extends LinkedTransferQueue { + HalfSyncLTQ() { super(); } + public void put(T x) { + if (ThreadLocalRandom.current().nextBoolean()) + super.put(x); + else { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + } + private final static long serialVersionUID = 42; + } + static void oneTest(int consumers, int iters) throws Exception { oneRun(new ArrayBlockingQueue(CAPACITY), consumers, iters); oneRun(new LinkedBlockingQueue(CAPACITY), consumers, iters); oneRun(new LinkedBlockingDeque(CAPACITY), consumers, iters); -// oneRun(new LinkedTransferQueue(), consumers, iters); + oneRun(new LinkedTransferQueue(), consumers, iters); + oneRun(new LTQasSQ(), consumers, iters); + oneRun(new HalfSyncLTQ(), consumers, iters); oneRun(new PriorityBlockingQueue(), consumers, iters); oneRun(new SynchronousQueue(), consumers, iters); if (print) diff --git a/jdk/test/java/util/concurrent/ConcurrentQueues/ConcurrentQueueLoops.java b/jdk/test/java/util/concurrent/ConcurrentQueues/ConcurrentQueueLoops.java index 9586d3d4a53..eea39293bd7 100644 --- a/jdk/test/java/util/concurrent/ConcurrentQueues/ConcurrentQueueLoops.java +++ b/jdk/test/java/util/concurrent/ConcurrentQueues/ConcurrentQueueLoops.java @@ -60,7 +60,7 @@ public class ConcurrentQueueLoops { //queues.add(new ArrayBlockingQueue(count, true)); queues.add(new LinkedBlockingQueue()); queues.add(new LinkedBlockingDeque()); -// queues.add(new LinkedTransferQueue()); + queues.add(new LinkedTransferQueue()); // Following additional implementations are available from: // http://gee.cs.oswego.edu/dl/concurrency-interest/index.html diff --git a/jdk/test/java/util/concurrent/ConcurrentQueues/GCRetention.java b/jdk/test/java/util/concurrent/ConcurrentQueues/GCRetention.java index c2ade907e9e..5d53618bdb7 100644 --- a/jdk/test/java/util/concurrent/ConcurrentQueues/GCRetention.java +++ b/jdk/test/java/util/concurrent/ConcurrentQueues/GCRetention.java @@ -43,7 +43,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingQueue; -// import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.PriorityBlockingQueue; import java.util.LinkedList; import java.util.PriorityQueue; @@ -70,7 +70,7 @@ public class GCRetention { queues.add(new PriorityBlockingQueue()); queues.add(new PriorityQueue()); queues.add(new LinkedList()); -// queues.add(new LinkedTransferQueue()); + queues.add(new LinkedTransferQueue()); // Following additional implementations are available from: // http://gee.cs.oswego.edu/dl/concurrency-interest/index.html diff --git a/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java b/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java index c767fa422ab..a684af73fb2 100644 --- a/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java +++ b/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java @@ -49,7 +49,7 @@ public class IteratorWeakConsistency { test(new LinkedBlockingDeque()); test(new LinkedBlockingDeque(20)); test(new ConcurrentLinkedQueue()); -// test(new LinkedTransferQueue()); + test(new LinkedTransferQueue()); // Other concurrent queues (e.g. ArrayBlockingQueue) do not // currently have weakly consistent iterators. // test(new ArrayBlockingQueue(20)); diff --git a/jdk/test/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java b/jdk/test/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java index 6051483f6c3..f1d926964f6 100644 --- a/jdk/test/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java +++ b/jdk/test/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java @@ -56,12 +56,11 @@ public class OfferRemoveLoops { testQueue(new ArrayBlockingQueue(10)); testQueue(new PriorityBlockingQueue(10)); testQueue(new ConcurrentLinkedQueue()); -// testQueue(new LinkedTransferQueue()); + testQueue(new LinkedTransferQueue()); } Random getRandom() { - return new Random(); - // return ThreadLocalRandom.current(); + return ThreadLocalRandom.current(); } void testQueue(final Queue q) throws Throwable { diff --git a/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java b/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java index 2019c658b7c..e7bcce44c0b 100644 --- a/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java +++ b/jdk/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java @@ -45,7 +45,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingQueue; -// import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.atomic.AtomicLong; import java.util.ArrayList; import java.util.Collection; @@ -67,7 +67,7 @@ public class RemovePollRace { queues.add(new ArrayBlockingQueue(count, true)); queues.add(new LinkedBlockingQueue()); queues.add(new LinkedBlockingDeque()); -// queues.add(new LinkedTransferQueue()); + queues.add(new LinkedTransferQueue()); // Following additional implementations are available from: // http://gee.cs.oswego.edu/dl/concurrency-interest/index.html diff --git a/jdk/test/java/util/concurrent/Phaser/Arrive.java b/jdk/test/java/util/concurrent/Phaser/Arrive.java new file mode 100644 index 00000000000..8d743b5b6af --- /dev/null +++ b/jdk/test/java/util/concurrent/Phaser/Arrive.java @@ -0,0 +1,94 @@ +/* + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6445158 + * @summary tests for Phaser.arrive() + */ + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Phaser; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; + +public class Arrive { + void test(String[] args) throws Throwable { + final int n = ThreadLocalRandom.current().nextInt(1, 10); + final int nthreads = n*3/2; + final Phaser startingGate = new Phaser(nthreads); + final Phaser phaser = new Phaser(n); + final List threads = new ArrayList(); + final AtomicInteger count0 = new AtomicInteger(0); + final AtomicInteger count1 = new AtomicInteger(0); + final Runnable task = new Runnable() { public void run() { + equal(startingGate.getPhase(), 0); + startingGate.arriveAndAwaitAdvance(); + equal(startingGate.getPhase(), 1); + int phase = phaser.arrive(); + if (phase == 0) + count0.getAndIncrement(); + else if (phase == 1) + count1.getAndIncrement(); + else + fail(); + }}; + for (int i = 0; i < nthreads; i++) + threads.add(new Thread(task)); + for (Thread thread : threads) + thread.start(); + for (Thread thread : threads) + thread.join(); + equal(count0.get(), n); + equal(count1.get(), nthreads-n); + equal(phaser.getPhase(), 1); + } + + //--------------------- Infrastructure --------------------------- + volatile int passed = 0, failed = 0; + void pass() {passed++;} + void fail() {failed++; Thread.dumpStack();} + void fail(String msg) {System.err.println(msg); fail();} + void unexpected(Throwable t) {failed++; t.printStackTrace();} + void check(boolean cond) {if (cond) pass(); else fail();} + void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + new Arrive().instanceMain(args);} + public void instanceMain(String[] args) throws Throwable { + try {test(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/jdk/test/java/util/concurrent/Phaser/Basic.java b/jdk/test/java/util/concurrent/Phaser/Basic.java new file mode 100644 index 00000000000..171a259dc8a --- /dev/null +++ b/jdk/test/java/util/concurrent/Phaser/Basic.java @@ -0,0 +1,407 @@ +/* + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6445158 + * @summary Basic tests for Phaser + * @author Chris Hegarty + */ + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import static java.util.concurrent.TimeUnit.*; + +public class Basic { + + private static void checkTerminated(final Phaser phaser) { + check(phaser.isTerminated()); + int unarriverParties = phaser.getUnarrivedParties(); + int registeredParties = phaser.getRegisteredParties(); + equal(phaser.arrive(), -1); + equal(phaser.arriveAndDeregister(), -1); + equal(phaser.arriveAndAwaitAdvance(), -1); + equal(phaser.bulkRegister(10), -1); + equal(phaser.getPhase(), -1); + equal(phaser.register(), -1); + try { + equal(phaser.awaitAdvanceInterruptibly(0), -1); + equal(phaser.awaitAdvanceInterruptibly(0, 10, SECONDS), -1); + } catch (Exception ie) { + unexpected(ie); + } + equal(phaser.getUnarrivedParties(), unarriverParties); + equal(phaser.getRegisteredParties(), registeredParties); + } + + private static void checkResult(Arriver a, Class c) { + Throwable t = a.result(); + if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) { + // t.printStackTrace(); + fail("Mismatch in thread " + + a.getName() + ": " + + t + ", " + + (c == null ? "" : c.getName())); + } else { + pass(); + } + } + + //---------------------------------------------------------------- + // Mechanism to get all test threads into "running" mode. + //---------------------------------------------------------------- + private static Phaser atTheStartingGate = new Phaser(3); + + private static void toTheStartingGate() { + try { + boolean expectNextPhase = false; + if (atTheStartingGate.getUnarrivedParties() == 1) { + expectNextPhase = true; + } + int phase = atTheStartingGate.getPhase(); + equal(phase, atTheStartingGate.arrive()); + int AwaitPhase = atTheStartingGate.awaitAdvanceInterruptibly(phase, + 10, + SECONDS); + if (expectNextPhase) check(AwaitPhase == (phase + 1)); + + pass(); + } catch (Throwable t) { + unexpected(t); + // reset(atTheStartingGate); + throw new Error(t); + } + } + + //---------------------------------------------------------------- + // Convenience methods for creating threads that call arrive, + // awaitAdvance, arriveAndAwaitAdvance, awaitAdvanceInterruptibly + //---------------------------------------------------------------- + private static abstract class Arriver extends Thread { + static AtomicInteger count = new AtomicInteger(1); + + Arriver() { + this("Arriver"); + } + + Arriver(String name) { + this.setName(name + ":" + count.getAndIncrement()); + this.setDaemon(true); + } + + private volatile Throwable result; + private volatile int phase; + protected void result(Throwable result) { this.result = result; } + public Throwable result() { return this.result; } + protected void phase(int phase) { this.phase = phase; } + public int phase() { return this.phase; } + } + + private static abstract class Awaiter extends Arriver { + Awaiter() { super("Awaiter"); } + Awaiter(String name) { super(name); } + } + + private static Arriver arriver(final Phaser phaser) { + return new Arriver() { public void run() { + toTheStartingGate(); + + try { phase(phaser.arrive()); } + catch (Throwable result) { result(result); }}}; + } + + private static AtomicInteger cycleArriveAwaitAdvance = new AtomicInteger(1); + + private static Awaiter awaiter(final Phaser phaser) { + return new Awaiter() { public void run() { + toTheStartingGate(); + + try { + if (cycleArriveAwaitAdvance.getAndIncrement() % 2 == 0) + phase(phaser.awaitAdvance(phaser.arrive())); + else + phase(phaser.arriveAndAwaitAdvance()); + } catch (Throwable result) { result(result); }}}; + } + + private static Awaiter awaiter(final Phaser phaser, + final long timeout, + final TimeUnit unit) { + return new Awaiter("InterruptibleWaiter") { public void run() { + toTheStartingGate(); + + try { + if (timeout < 0) + phase(phaser.awaitAdvanceInterruptibly(phaser.arrive())); + else + phase(phaser.awaitAdvanceInterruptibly(phaser.arrive(), + timeout, + unit)); + } catch (Throwable result) { result(result); }}}; + } + + // Returns an infinite lazy list of all possible arriver/awaiter combinations. + private static Iterator arriverIterator(final Phaser phaser) { + return new Iterator() { + int i = 0; + public boolean hasNext() { return true; } + public Arriver next() { + switch ((i++)&7) { + case 0: case 4: + return arriver(phaser); + case 1: case 5: + return awaiter(phaser); + case 2: case 6: case 7: + return awaiter(phaser, -1, SECONDS); + default: + return awaiter(phaser, 10, SECONDS); }} + public void remove() {throw new UnsupportedOperationException();}}; + } + + // Returns an infinite lazy list of all possible awaiter only combinations. + private static Iterator awaiterIterator(final Phaser phaser) { + return new Iterator() { + int i = 0; + public boolean hasNext() { return true; } + public Awaiter next() { + switch ((i++)&7) { + case 1: case 4: case 7: + return awaiter(phaser); + case 2: case 5: + return awaiter(phaser, -1, SECONDS); + default: + return awaiter(phaser, 10, SECONDS); }} + public void remove() {throw new UnsupportedOperationException();}}; + } + + private static void realMain(String[] args) throws Throwable { + + Thread.currentThread().setName("mainThread"); + + //---------------------------------------------------------------- + // Normal use + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(3); + equal(phaser.getRegisteredParties(), 3); + equal(phaser.getArrivedParties(), 0); + equal(phaser.getPhase(), 0); + check(phaser.getRoot().equals(phaser)); + equal(phaser.getParent(), null); + check(!phaser.isTerminated()); + + Iterator arrivers = arriverIterator(phaser); + int phase = 0; + for (int i = 0; i < 10; i++) { + equal(phaser.getPhase(), phase++); + Arriver a1 = arrivers.next(); a1.start(); + Arriver a2 = arrivers.next(); a2.start(); + toTheStartingGate(); + phaser.arriveAndAwaitAdvance(); + a1.join(); + a2.join(); + checkResult(a1, null); + checkResult(a2, null); + check(!phaser.isTerminated()); + equal(phaser.getRegisteredParties(), 3); + equal(phaser.getArrivedParties(), 0); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // One thread interrupted + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(3); + Iterator arrivers = arriverIterator(phaser); + int phase = phaser.getPhase(); + for (int i = 0; i < 4; i++) { + check(phaser.getPhase() == phase); + Awaiter a1 = awaiter(phaser, 10, SECONDS); a1.start(); + Arriver a2 = arrivers.next(); a2.start(); + toTheStartingGate(); + a1.interrupt(); + a1.join(); + phaser.arriveAndAwaitAdvance(); + a2.join(); + checkResult(a1, InterruptedException.class); + checkResult(a2, null); + check(!phaser.isTerminated()); + equal(phaser.getRegisteredParties(), 3); + equal(phaser.getArrivedParties(), 0); + phase++; + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Phaser is terminated while threads are waiting + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(3); + Iterator awaiters = awaiterIterator(phaser); + for (int i = 0; i < 4; i++) { + Arriver a1 = awaiters.next(); a1.start(); + Arriver a2 = awaiters.next(); a2.start(); + toTheStartingGate(); + while (phaser.getArrivedParties() < 2) Thread.yield(); + phaser.forceTermination(); + a1.join(); + a2.join(); + check(a1.phase == -1); + check(a2.phase == -1); + int arrivedParties = phaser.getArrivedParties(); + checkTerminated(phaser); + equal(phaser.getArrivedParties(), arrivedParties); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Adds new unarrived parties to this phaser + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(1); + Iterator arrivers = arriverIterator(phaser); + LinkedList arriverList = new LinkedList(); + int phase = phaser.getPhase(); + for (int i = 1; i < 5; i++) { + atTheStartingGate = new Phaser(1+(3*i)); + check(phaser.getPhase() == phase); + // register 3 more + phaser.register(); phaser.register(); phaser.register(); + for (int z=0; z<(3*i); z++) { + arriverList.add(arrivers.next()); + } + for (Arriver arriver : arriverList) + arriver.start(); + + toTheStartingGate(); + phaser.arriveAndAwaitAdvance(); + + for (Arriver arriver : arriverList) { + arriver.join(); + checkResult(arriver, null); + } + equal(phaser.getRegisteredParties(), 1 + (3*i)); + equal(phaser.getArrivedParties(), 0); + arriverList.clear(); + phase++; + } + atTheStartingGate = new Phaser(3); + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // One thread timed out + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(3); + Iterator arrivers = arriverIterator(phaser); + for (long timeout : new long[] { 0L, 5L }) { + for (int i = 0; i < 2; i++) { + Awaiter a1 = awaiter(phaser, timeout, SECONDS); a1.start(); + Arriver a2 = arrivers.next(); a2.start(); + toTheStartingGate(); + a1.join(); + checkResult(a1, TimeoutException.class); + phaser.arrive(); + a2.join(); + checkResult(a2, null); + check(!phaser.isTerminated()); + } + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Barrier action completed normally + //---------------------------------------------------------------- + try { + final AtomicInteger count = new AtomicInteger(0); + final Phaser[] kludge = new Phaser[1]; + Phaser phaser = new Phaser(3) { + @Override + protected boolean onAdvance(int phase, int registeredParties) { + int countPhase = count.getAndIncrement(); + equal(countPhase, phase); + equal(kludge[0].getPhase(), phase); + equal(kludge[0].getRegisteredParties(), registeredParties); + if (phase >= 3) + return true; // terminate + + return false; + } + }; + kludge[0] = phaser; + equal(phaser.getRegisteredParties(), 3); + Iterator awaiters = awaiterIterator(phaser); + for (int i = 0; i < 4; i++) { + Awaiter a1 = awaiters.next(); a1.start(); + Awaiter a2 = awaiters.next(); a2.start(); + toTheStartingGate(); + while (phaser.getArrivedParties() < 2) Thread.yield(); + phaser.arrive(); + a1.join(); + a2.join(); + checkResult(a1, null); + checkResult(a2, null); + equal(count.get(), i+1); + if (i < 3) { + check(!phaser.isTerminated()); + equal(phaser.getRegisteredParties(), 3); + equal(phaser.getArrivedParties(), 0); + equal(phaser.getUnarrivedParties(), 3); + equal(phaser.getPhase(), count.get()); + } else + checkTerminated(phaser); + } + } catch (Throwable t) { unexpected(t); } + + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void fail() {failed++; Thread.dumpStack();} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void check(boolean cond) {if (cond) pass(); else fail();} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java index 9df0235ec8f..a89aa182a0e 100644 --- a/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java +++ b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java @@ -20,6 +20,17 @@ * have any questions. */ +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + /* * @test * @bug 6725789 diff --git a/jdk/test/java/util/concurrent/forkjoin/Integrate.java b/jdk/test/java/util/concurrent/forkjoin/Integrate.java new file mode 100644 index 00000000000..0adfeecaa2e --- /dev/null +++ b/jdk/test/java/util/concurrent/forkjoin/Integrate.java @@ -0,0 +1,265 @@ +/* + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6865571 + * @summary Numerical Integration using fork/join + * @run main Integrate reps=1 forkPolicy=dynamic + * @run main Integrate reps=1 forkPolicy=serial + * @run main Integrate reps=1 forkPolicy=fork + */ + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveAction; + +/** + * Sample program using Gaussian Quadrature for numerical integration. + * This version uses a simplified hardwired function. Inspired by a + * + * Filaments demo program. + */ +public final class Integrate { + + static final double errorTolerance = 1.0e-11; + /** for time conversion */ + static final long NPS = (1000L * 1000 * 1000); + + static final int SERIAL = -1; + static final int DYNAMIC = 0; + static final int FORK = 1; + + // the function to integrate + static double computeFunction(double x) { + return (x * x + 1.0) * x; + } + + static final double start = 0.0; + static final double end = 1536.0; + /* + * The number of recursive calls for + * integrate from start to end. + * (Empirically determined) + */ + static final int calls = 263479047; + + static String keywordValue(String[] args, String keyword) { + for (String arg : args) + if (arg.startsWith(keyword)) + return arg.substring(keyword.length() + 1); + return null; + } + + static int intArg(String[] args, String keyword, int defaultValue) { + String val = keywordValue(args, keyword); + return (val == null) ? defaultValue : Integer.parseInt(val); + } + + static int policyArg(String[] args, String keyword, int defaultPolicy) { + String val = keywordValue(args, keyword); + if (val == null) return defaultPolicy; + if (val.equals("dynamic")) return DYNAMIC; + if (val.equals("serial")) return SERIAL; + if (val.equals("fork")) return FORK; + throw new Error(); + } + + /** + * Usage: Integrate [procs=N] [reps=N] forkPolicy=serial|dynamic|fork + */ + public static void main(String[] args) throws Exception { + final int procs = intArg(args, "procs", + Runtime.getRuntime().availableProcessors()); + final int forkPolicy = policyArg(args, "forkPolicy", DYNAMIC); + + ForkJoinPool g = new ForkJoinPool(procs); + System.out.println("Integrating from " + start + " to " + end + + " forkPolicy = " + forkPolicy); + long lastTime = System.nanoTime(); + + for (int reps = intArg(args, "reps", 10); reps > 0; reps--) { + double a; + if (forkPolicy == SERIAL) + a = SQuad.computeArea(g, start, end); + else if (forkPolicy == FORK) + a = FQuad.computeArea(g, start, end); + else + a = DQuad.computeArea(g, start, end); + long now = System.nanoTime(); + double s = (double) (now - lastTime) / NPS; + lastTime = now; + System.out.printf("Calls/sec: %12d", (long) (calls / s)); + System.out.printf(" Time: %7.3f", s); + System.out.printf(" Area: %12.1f", a); + System.out.println(); + } + System.out.println(g); + g.shutdown(); + } + + + // Sequential version + static final class SQuad extends RecursiveAction { + static double computeArea(ForkJoinPool pool, double l, double r) { + SQuad q = new SQuad(l, r, 0); + pool.invoke(q); + return q.area; + } + + final double left; // lower bound + final double right; // upper bound + double area; + + SQuad(double l, double r, double a) { + this.left = l; this.right = r; this.area = a; + } + + public final void compute() { + double l = left; + double r = right; + area = recEval(l, r, (l * l + 1.0) * l, (r * r + 1.0) * r, area); + } + + static final double recEval(double l, double r, double fl, + double fr, double a) { + double h = (r - l) * 0.5; + double c = l + h; + double fc = (c * c + 1.0) * c; + double hh = h * 0.5; + double al = (fl + fc) * hh; + double ar = (fr + fc) * hh; + double alr = al + ar; + if (Math.abs(alr - a) <= errorTolerance) + return alr; + else + return recEval(c, r, fc, fr, ar) + recEval(l, c, fl, fc, al); + } + + } + + //.................................... + + // ForkJoin version + static final class FQuad extends RecursiveAction { + static double computeArea(ForkJoinPool pool, double l, double r) { + FQuad q = new FQuad(l, r, 0); + pool.invoke(q); + return q.area; + } + + final double left; // lower bound + final double right; // upper bound + double area; + + FQuad(double l, double r, double a) { + this.left = l; this.right = r; this.area = a; + } + + public final void compute() { + double l = left; + double r = right; + area = recEval(l, r, (l * l + 1.0) * l, (r * r + 1.0) * r, area); + } + + static final double recEval(double l, double r, double fl, + double fr, double a) { + double h = (r - l) * 0.5; + double c = l + h; + double fc = (c * c + 1.0) * c; + double hh = h * 0.5; + double al = (fl + fc) * hh; + double ar = (fr + fc) * hh; + double alr = al + ar; + if (Math.abs(alr - a) <= errorTolerance) + return alr; + FQuad q = new FQuad(l, c, al); + q.fork(); + ar = recEval(c, r, fc, fr, ar); + if (!q.tryUnfork()) { + q.quietlyHelpJoin(); + return ar + q.area; + } + return ar + recEval(l, c, fl, fc, al); + } + + } + + // ........................... + + // Version using on-demand Fork + static final class DQuad extends RecursiveAction { + static double computeArea(ForkJoinPool pool, double l, double r) { + DQuad q = new DQuad(l, r, 0); + pool.invoke(q); + return q.area; + } + + final double left; // lower bound + final double right; // upper bound + double area; + + DQuad(double l, double r, double a) { + this.left = l; this.right = r; this.area = a; + } + + public final void compute() { + double l = left; + double r = right; + area = recEval(l, r, (l * l + 1.0) * l, (r * r + 1.0) * r, area); + } + + static final double recEval(double l, double r, double fl, + double fr, double a) { + double h = (r - l) * 0.5; + double c = l + h; + double fc = (c * c + 1.0) * c; + double hh = h * 0.5; + double al = (fl + fc) * hh; + double ar = (fr + fc) * hh; + double alr = al + ar; + if (Math.abs(alr - a) <= errorTolerance) + return alr; + DQuad q = null; + if (getSurplusQueuedTaskCount() <= 3) + (q = new DQuad(l, c, al)).fork(); + ar = recEval(c, r, fc, fr, ar); + if (q != null && !q.tryUnfork()) { + q.quietlyHelpJoin(); + return ar + q.area; + } + return ar + recEval(l, c, fl, fc, al); + } + + } + +} diff --git a/jdk/test/java/util/concurrent/forkjoin/NQueensCS.java b/jdk/test/java/util/concurrent/forkjoin/NQueensCS.java new file mode 100644 index 00000000000..d36e5814f33 --- /dev/null +++ b/jdk/test/java/util/concurrent/forkjoin/NQueensCS.java @@ -0,0 +1,174 @@ +/* + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6865571 + * @summary Solve NQueens using fork/join + * @run main NQueensCS maxBoardSize=11 reps=1 + * @run main NQueensCS maxBoardSize=11 reps=1 procs=8 + */ + +import java.util.Arrays; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveAction; + +public class NQueensCS extends RecursiveAction { + + static long lastStealCount; + static int boardSize; + + static final int[] expectedSolutions = new int[] { + 0, 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200, + 73712, 365596, 2279184, 14772512, 95815104, 666090624 + }; // see http://www.durangobill.com/N_Queens.html + + static String keywordValue(String[] args, String keyword) { + for (String arg : args) + if (arg.startsWith(keyword)) + return arg.substring(keyword.length() + 1); + return null; + } + + static int intArg(String[] args, String keyword, int defaultValue) { + String val = keywordValue(args, keyword); + return (val == null) ? defaultValue : Integer.parseInt(val); + } + + /** for time conversion */ + static final long NPS = (1000L * 1000L * 1000L); + + /** + * Usage: NQueensCS [minBoardSize=N] [maxBoardSize=N] [procs=N] [reps=N] + */ + public static void main(String[] args) throws Exception { + // Board sizes too small: hard to measure well. + // Board sizes too large: take too long to run. + final int minBoardSize = intArg(args, "minBoardSize", 8); + final int maxBoardSize = intArg(args, "maxBoardSize", 15); + + final int procs = intArg(args, "procs", 0); + + for (int reps = intArg(args, "reps", 10); reps > 0; reps--) { + ForkJoinPool g = (procs == 0) ? + new ForkJoinPool() : + new ForkJoinPool(procs); + lastStealCount = g.getStealCount(); + for (int i = minBoardSize; i <= maxBoardSize; i++) + test(g, i); + System.out.println(g); + g.shutdown(); + } + } + + static void test(ForkJoinPool g, int i) throws Exception { + boardSize = i; + int ps = g.getParallelism(); + long start = System.nanoTime(); + NQueensCS task = new NQueensCS(new int[0]); + g.invoke(task); + int solutions = task.solutions; + long time = System.nanoTime() - start; + double secs = (double) time / NPS; + if (solutions != expectedSolutions[i]) + throw new Error(); + System.out.printf("NQueensCS %3d", i); + System.out.printf(" Time: %7.3f", secs); + long sc = g.getStealCount(); + long ns = sc - lastStealCount; + lastStealCount = sc; + System.out.printf(" Steals/t: %5d", ns/ps); + System.out.println(); + } + + // Boards are represented as arrays where each cell + // holds the column number of the queen in that row + + final int[] sofar; + NQueensCS nextSubtask; // to link subtasks + int solutions; + NQueensCS(int[] a) { + this.sofar = a; + } + + public final void compute() { + NQueensCS subtasks; + int bs = boardSize; + if (sofar.length >= bs) + solutions = 1; + else if ((subtasks = explore(sofar, bs)) != null) + solutions = processSubtasks(subtasks); + } + + private static NQueensCS explore(int[] array, int bs) { + int row = array.length; + NQueensCS s = null; // subtask list + outer: + for (int q = 0; q < bs; ++q) { + for (int i = 0; i < row; i++) { + int p = array[i]; + if (q == p || q == p - (row - i) || q == p + (row - i)) + continue outer; // attacked + } + NQueensCS first = s; // lag forks to ensure 1 kept + if (first != null) + first.fork(); + int[] next = Arrays.copyOf(array, row+1); + next[row] = q; + NQueensCS subtask = new NQueensCS(next); + subtask.nextSubtask = first; + s = subtask; + } + return s; + } + + private static int processSubtasks(NQueensCS s) { + // Always run first the task held instead of forked + s.compute(); + int ns = s.solutions; + s = s.nextSubtask; + // Then the unstolen ones + while (s != null && s.tryUnfork()) { + s.compute(); + ns += s.solutions; + s = s.nextSubtask; + } + // Then wait for the stolen ones + while (s != null) { + s.join(); + ns += s.solutions; + s = s.nextSubtask; + } + return ns; + } +} diff --git a/jdk/test/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java b/jdk/test/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java index 62ef49921a7..fb1c7b5b5ca 100644 --- a/jdk/test/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java +++ b/jdk/test/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java @@ -115,7 +115,7 @@ public final class CancelledLockLoops { finally { lock.unlock(); } - if (completed != 2) + if (c != 2) throw new Error("Completed != 2"); int r = result; if (r == 0) // avoid overoptimization diff --git a/jdk/test/java/util/concurrent/locks/ReentrantReadWriteLock/RWMap.java b/jdk/test/java/util/concurrent/locks/ReentrantReadWriteLock/RWMap.java index e81c676c6fa..6bcc71c3120 100644 --- a/jdk/test/java/util/concurrent/locks/ReentrantReadWriteLock/RWMap.java +++ b/jdk/test/java/util/concurrent/locks/ReentrantReadWriteLock/RWMap.java @@ -30,6 +30,7 @@ * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ + import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; diff --git a/jdk/test/javax/swing/Security/6657138/ComponentTest.java b/jdk/test/javax/swing/Security/6657138/ComponentTest.java new file mode 100644 index 00000000000..a1a3a7b3c6f --- /dev/null +++ b/jdk/test/javax/swing/Security/6657138/ComponentTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657138 + * @summary Verifies that buttons and labels work well after the fix for 6657138 + * @author Alexander Potochkin + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import java.awt.*; + +public class ComponentTest extends JFrame { + private static JFrame frame; + + public ComponentTest() { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setLayout(new FlowLayout()); + add(new JButton("JButton")); + add(new JToggleButton("JToggleButton")); + add(new JCheckBox("JCheckBox")); + add(new JRadioButton("JRadioButton")); + add(new JLabel("JLabel")); + pack(); + setLocationRelativeTo(null); + } + + + public static void main(String[] args) throws Exception { + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame = new ComponentTest(); + frame.setVisible(true); + } + }); + toolkit.realSync(); + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + for (final UIManager.LookAndFeelInfo laf : lafs) { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (Exception e) { + new RuntimeException(e); + } + SwingUtilities.updateComponentTreeUI(frame); + } + }); + toolkit.realSync(); + } + } +} diff --git a/jdk/test/javax/swing/Security/6657138/bug6657138.java b/jdk/test/javax/swing/Security/6657138/bug6657138.java new file mode 100644 index 00000000000..5a3562d256e --- /dev/null +++ b/jdk/test/javax/swing/Security/6657138/bug6657138.java @@ -0,0 +1,103 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657138 + * @summary Verifies that buttons and labels don't share their ui's across appContexts + * @author Alexander Potochkin + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import javax.swing.plaf.ButtonUI; +import javax.swing.plaf.ComponentUI; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class bug6657138 implements Runnable { + + private static Map> componentMap = + Collections.synchronizedMap( + new HashMap>()); + + public void run() { + SunToolkit.createNewAppContext(); + try { + testUIMap(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void testUIMap() throws Exception { + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + Set components = componentMap.keySet(); + for (JComponent c : components) { + Map uiMap = componentMap.get(c); + + for (UIManager.LookAndFeelInfo laf : lafs) { + if ("Nimbus".equals(laf.getName())) { + // for some unclear reasons + // Nimbus ui delegate for a button is null + // when this method is called from the new AppContext + continue; + } + String className = laf.getClassName(); + UIManager.setLookAndFeel(className); + ComponentUI ui = UIManager.getUI(c); + if (ui == null) { + throw new RuntimeException("UI is null for " + c); + } + if (ui == uiMap.get(laf.getName())) { + throw new RuntimeException( + "Two AppContexts share the same UI delegate! \n" + + c + "\n" + ui); + } + uiMap.put(laf.getName(), ui); + } + } + } + + public static void main(String[] args) throws Exception { + componentMap.put(new JButton("JButton"), + new HashMap()); + componentMap.put(new JToggleButton("JToggleButton"), + new HashMap()); + componentMap.put(new JRadioButton("JRadioButton"), + new HashMap()); + componentMap.put(new JCheckBox("JCheckBox"), + new HashMap()); + componentMap.put(new JCheckBox("JLabel"), + new HashMap()); + testUIMap(); + ThreadGroup group = new ThreadGroup("6657138"); + Thread thread = new Thread(group, new bug6657138()); + thread.start(); + thread.join(); + } +} + diff --git a/jdk/test/javax/swing/ToolTipManager/Test6657026.java b/jdk/test/javax/swing/ToolTipManager/Test6657026.java new file mode 100644 index 00000000000..f9e23b988bb --- /dev/null +++ b/jdk/test/javax/swing/ToolTipManager/Test6657026.java @@ -0,0 +1,74 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared ToolTipManager in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; +import javax.swing.ToolTipManager; + +public class Test6657026 implements Runnable { + + private static final int DISMISS = 4000; + private static final int INITIAL = 750; + private static final int RESHOW = 500; + + public static void main(String[] args) throws InterruptedException { + ToolTipManager manager = ToolTipManager.sharedInstance(); + if (DISMISS != manager.getDismissDelay()) { + throw new Error("unexpected dismiss delay"); + } + if (INITIAL != manager.getInitialDelay()) { + throw new Error("unexpected initial delay"); + } + if (RESHOW != manager.getReshowDelay()) { + throw new Error("unexpected reshow delay"); + } + manager.setDismissDelay(DISMISS + 1); + manager.setInitialDelay(INITIAL + 1); + manager.setReshowDelay(RESHOW + 1); + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + ToolTipManager manager = ToolTipManager.sharedInstance(); + if (DISMISS != manager.getDismissDelay()) { + throw new Error("shared dismiss delay"); + } + if (INITIAL != manager.getInitialDelay()) { + throw new Error("shared initial delay"); + } + if (RESHOW != manager.getReshowDelay()) { + throw new Error("shared reshow delay"); + } + } +} diff --git a/jdk/test/javax/swing/UIManager/Test6657026.java b/jdk/test/javax/swing/UIManager/Test6657026.java new file mode 100644 index 00000000000..7b93a22196c --- /dev/null +++ b/jdk/test/javax/swing/UIManager/Test6657026.java @@ -0,0 +1,59 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared UIManager in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; + +public class Test6657026 implements Runnable { + + public static void main(String[] args) throws Exception { + if (UIManager.getInstalledLookAndFeels().length == 0) { + throw new Error("unexpected amount of look&feels"); + } + UIManager.setInstalledLookAndFeels(new LookAndFeelInfo[0]); + if (UIManager.getInstalledLookAndFeels().length != 0) { + throw new Error("unexpected amount of look&feels"); + } + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + if (UIManager.getInstalledLookAndFeels().length == 0) { + throw new Error("shared look&feels"); + } + } +} diff --git a/jdk/test/javax/swing/plaf/basic/BasicSplitPaneUI/Test6657026.java b/jdk/test/javax/swing/plaf/basic/BasicSplitPaneUI/Test6657026.java new file mode 100644 index 00000000000..16080416f73 --- /dev/null +++ b/jdk/test/javax/swing/plaf/basic/BasicSplitPaneUI/Test6657026.java @@ -0,0 +1,82 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared BasicSplitPaneUI in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import java.awt.event.ActionEvent; +import java.util.Set; +import javax.swing.JSplitPane; +import javax.swing.plaf.basic.BasicSplitPaneUI; + +public class Test6657026 extends BasicSplitPaneUI implements Runnable { + + public static void main(String[] args) throws InterruptedException { + if (new JSplitPane().getFocusTraversalKeys(0).isEmpty()){ + throw new Error("unexpected traversal keys"); + } + new JSplitPane() { + public void setFocusTraversalKeys(int id, Set keystrokes) { + keystrokes.clear(); + super.setFocusTraversalKeys(id, keystrokes); + } + }; + if (new JSplitPane().getFocusTraversalKeys(0).isEmpty()) { + throw new Error("shared traversal keys"); + } + KEYBOARD_DIVIDER_MOVE_OFFSET = -KEYBOARD_DIVIDER_MOVE_OFFSET; + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + if (new JSplitPane().getFocusTraversalKeys(0).isEmpty()) { + throw new Error("shared traversal keys"); + } + JSplitPane pane = new JSplitPane(); + pane.setUI(this); + + createFocusListener().focusGained(null); // allows actions + test(pane, "positiveIncrement", 3); + test(pane, "negativeIncrement", 0); + } + + private static void test(JSplitPane pane, String action, int expected) { + ActionEvent event = new ActionEvent(pane, expected, action); + pane.getActionMap().get(action).actionPerformed(event); + int actual = pane.getDividerLocation(); + if (actual != expected) { + throw new Error(actual + ", but expected " + expected); + } + } +} diff --git a/jdk/test/javax/swing/plaf/metal/MetalBorders/Test6657026.java b/jdk/test/javax/swing/plaf/metal/MetalBorders/Test6657026.java new file mode 100644 index 00000000000..194b310f450 --- /dev/null +++ b/jdk/test/javax/swing/plaf/metal/MetalBorders/Test6657026.java @@ -0,0 +1,91 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests constancy of borders + * @author Sergey Malenkov + */ + +import java.awt.Insets; +import javax.swing.border.Border; +import javax.swing.plaf.metal.MetalBorders.ButtonBorder; +import javax.swing.plaf.metal.MetalBorders.MenuBarBorder; +import javax.swing.plaf.metal.MetalBorders.MenuItemBorder; +import javax.swing.plaf.metal.MetalBorders.PopupMenuBorder; + +public class Test6657026 { + + private static final Insets NEGATIVE = new Insets(Integer.MIN_VALUE, + Integer.MIN_VALUE, + Integer.MIN_VALUE, + Integer.MIN_VALUE); + + public static void main(String[] args) { + new ButtonBorder() {{borderInsets = NEGATIVE;}}; + new MenuBarBorder() {{borderInsets = NEGATIVE;}}; + new MenuItemBorder() {{borderInsets = NEGATIVE;}}; + new PopupMenuBorder() {{borderInsets = NEGATIVE;}}; + + test(create("ButtonBorder")); + test(create("MenuBarBorder")); + test(create("MenuItemBorder")); + test(create("PopupMenuBorder")); + + test(create("Flush3DBorder")); + test(create("InternalFrameBorder")); + // NOT USED: test(create("FrameBorder")); + // NOT USED: test(create("DialogBorder")); + test(create("PaletteBorder")); + test(create("OptionDialogBorder")); + test(create("ScrollPaneBorder")); + } + + private static Border create(String name) { + try { + name = "javax.swing.plaf.metal.MetalBorders$" + name; + return (Border) Class.forName(name).newInstance(); + } + catch (Exception exception) { + throw new Error("unexpected exception", exception); + } + } + + private static void test(Border border) { + Insets actual = border.getBorderInsets(null); + if (NEGATIVE.equals(actual)) { + throw new Error("unexpected insets in " + border.getClass()); + } + Insets expected = (Insets) actual.clone(); + // modify + actual.top++; + actual.left++; + actual.right++; + actual.bottom++; + // validate + if (!expected.equals(border.getBorderInsets(null))) { + throw new Error("shared insets in " + border.getClass()); + } + } +} diff --git a/jdk/test/javax/swing/plaf/metal/MetalBumps/Test6657026.java b/jdk/test/javax/swing/plaf/metal/MetalBumps/Test6657026.java new file mode 100644 index 00000000000..f8041629346 --- /dev/null +++ b/jdk/test/javax/swing/plaf/metal/MetalBumps/Test6657026.java @@ -0,0 +1,238 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared MetalBumps in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; +import java.text.AttributedCharacterIterator; +import javax.swing.Icon; +import javax.swing.plaf.metal.MetalBorders.ToolBarBorder; + +public class Test6657026 extends ToolBarBorder implements Runnable { + + public static void main(String[] args) throws Exception { + new Test6657026().test(); + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + test(); + } + + private void test() { + MyGraphics mg = new MyGraphics(); + Icon icon = bumps; + icon.paintIcon(mg.component, mg, 0, 0); + if (mg.image != null) { + boolean failed = true; + int value = mg.image.getRGB(0, 0); + for (int x = 0; x < mg.image.getWidth(); x++) { + for (int y = 0; y < mg.image.getHeight(); y++) { + int current = mg.image.getRGB(x, y); + if (current != value) { + mg.image.setRGB(x, y, value); + failed = false; + } + + } + } + if (failed) { + throw new Error("shared metal bumps"); + } + } + } + + private static class MyGraphics extends Graphics { + + private final Component component = new Component() {}; + private BufferedImage image; + + public Graphics create() { + return null; // TODO: check + } + + public void translate(int x, int y) { + // TODO: check + } + + public Color getColor() { + return null; // TODO: check + } + + public void setColor(Color color) { + // TODO: check + } + + public void setPaintMode() { + // TODO: check + } + + public void setXORMode(Color c1) { + // TODO: check + } + + public Font getFont() { + return null; // TODO: check + } + + public void setFont(Font font) { + // TODO: check + } + + public FontMetrics getFontMetrics(Font font) { + return null; // TODO: check + } + + public Rectangle getClipBounds() { + return null; // TODO: check + } + + public void clipRect(int x, int y, int width, int height) { + // TODO: check + } + + public void setClip(int x, int y, int width, int height) { + // TODO: check + } + + public Shape getClip() { + return null; // TODO: check + } + + public void setClip(Shape clip) { + // TODO: check + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + // TODO: check + } + + public void drawLine(int x1, int y1, int x2, int y2) { + // TODO: check + } + + public void fillRect(int x, int y, int width, int height) { + // TODO: check + } + + public void clearRect(int x, int y, int width, int height) { + // TODO: check + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + // TODO: check + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + // TODO: check + } + + public void drawOval(int x, int y, int width, int height) { + // TODO: check + } + + public void fillOval(int x, int y, int width, int height) { + // TODO: check + } + + public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + // TODO: check + } + + public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + // TODO: check + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { + // TODO: check + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { + // TODO: check + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { + // TODO: check + } + + public void drawString(String str, int x, int y) { + // TODO: check + } + + public void drawString(AttributedCharacterIterator iterator, int x, int y) { + // TODO: check + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + return false; // TODO: check + } + + public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { + return false; // TODO: check + } + + public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { + return false; // TODO: check + } + + public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { + return false; // TODO: check + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { + if (img instanceof BufferedImage) { + this.image = (BufferedImage) img; + } + return false; // TODO: check + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { + return false; // TODO: check + } + + public void dispose() { + // TODO: check + } + } +} diff --git a/jdk/test/javax/swing/plaf/metal/MetalInternalFrameUI/Test6657026.java b/jdk/test/javax/swing/plaf/metal/MetalInternalFrameUI/Test6657026.java new file mode 100644 index 00000000000..bbfec61c5ba --- /dev/null +++ b/jdk/test/javax/swing/plaf/metal/MetalInternalFrameUI/Test6657026.java @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared MetalInternalFrameUI in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import javax.swing.JInternalFrame; +import javax.swing.JPanel; +import javax.swing.UIManager; +import javax.swing.plaf.metal.MetalInternalFrameUI; +import javax.swing.plaf.metal.MetalLookAndFeel; + +public class Test6657026 extends MetalInternalFrameUI implements Runnable { + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + + new JInternalFrame().setContentPane(new JPanel()); + } + + public Test6657026() { + super(null); + } + + public void run() { + SunToolkit.createNewAppContext(); + IS_PALETTE = JInternalFrame.CONTENT_PANE_PROPERTY; + } +} diff --git a/jdk/test/javax/swing/plaf/metal/MetalSliderUI/Test6657026.java b/jdk/test/javax/swing/plaf/metal/MetalSliderUI/Test6657026.java new file mode 100644 index 00000000000..250889acd89 --- /dev/null +++ b/jdk/test/javax/swing/plaf/metal/MetalSliderUI/Test6657026.java @@ -0,0 +1,67 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared MetalSliderUI in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import javax.swing.JSlider; +import javax.swing.UIManager; +import javax.swing.plaf.metal.MetalLookAndFeel; +import javax.swing.plaf.metal.MetalSliderUI; + +public class Test6657026 extends MetalSliderUI implements Runnable { + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + JSlider slider = new JSlider(); + test(slider); + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + + test(slider); + } + + public void run() { + SunToolkit.createNewAppContext(); + JSlider slider = new JSlider(); + test(slider); + tickLength = -10000; + } + + private static void test(JSlider slider) { + MetalSliderUI ui = (MetalSliderUI) slider.getUI(); + int actual = ui.getTickLength(); + if (actual != 11) { + throw new Error(actual + ", but expected 11"); + } + } +} diff --git a/jdk/test/start-Xvfb.sh b/jdk/test/start-Xvfb.sh new file mode 100644 index 00000000000..be68040e231 --- /dev/null +++ b/jdk/test/start-Xvfb.sh @@ -0,0 +1,87 @@ +#!/bin/sh -f +# +# Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# Original Author: Tim Bell +# +usage() { + echo "Starts up an Xvfb dummy X server with fvwm2 window manager" + echo " usage:" + echo " ${0} display_number_file" + echo " display_number_file gets display number when it's ready" + exit + } +# +currentDir=`pwd` +rm -f $1 +DD=":$$" +DISPLAY=${DD} +export DISPLAY +cd /tmp +# +if [ ! -x "/usr/bin/X11/Xvfb" ]; then + # We have Solaris-flavored X windows, and the /usr/openwin Xvfb is + # a simple wrapper script around the Xsun server. Massage the + # arguments: server number must be first; others are slightly + # different. + # + # Also the default Visual Class (DirectColor) triggers an awt bug + # (probably 4131533/6505852) and some tests will loop endlessly + # when they hit the display. The workaround is: + # 1) Ask for PseudoColor instead. + # 2) Omit 32-bit depth. + /usr/bin/nohup /usr/openwin/bin/Xvfb ${DISPLAY} -dev vfb screen 0 1280x1024x24 pixdepths 8 16 24 defclass PseudoColor > ${currentDir}/nohup.$$ 2>&1 & +else + # Linux... + /usr/bin/nohup /usr/bin/X11/Xvfb -fbdir ${currentDir} -pixdepths 8 16 24 32 ${DISPLAY} > ${currentDir}/nohup.$$ 2>&1 & +fi +WM="/usr/bin/X11/fvwm2" +if [ ! -x ${WM} ] ; then + WM="/opt/sfw/bin/fvwm2" +fi +# +# Wait for Xvfb to initialize: +sleep 5 +# +if [ -x "${WM}" ]; then +# 2 JCK tests require a window manager +# mwm fails (key name errors) and twm fails (hangs), +# but fvwm2 works well. + /usr/bin/nohup ${WM} -display ${DISPLAY} -replace -f /dev/null > ${currentDir}/nohup.$$ 2>&1 & +else + echo "Error: ${WM} not found" + exit 1 +fi +# +# Wait some more to see if the xhost command gets through: +sleep 10 +# Allow access to all - this is a brute force approach, +# but I do not see how it could be a security problem... +DISPLAY="${DD}" xhost + +# +echo "Virtual frame buffer started on ${DISPLAY}" +echo "$$" > $1 +wait diff --git a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java new file mode 100644 index 00000000000..891967fd7e7 --- /dev/null +++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java @@ -0,0 +1,442 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * + * @bug 6861062 + * @summary Disable MD2 support + * + * @run main/othervm CPBuilder trustAnchor_SHA1withRSA_1024 0 true + * @run main/othervm CPBuilder trustAnchor_SHA1withRSA_512 0 true + * @run main/othervm CPBuilder intermediate_SHA1withRSA_1024_1024 1 true + * @run main/othervm CPBuilder intermediate_SHA1withRSA_1024_512 1 true + * @run main/othervm CPBuilder intermediate_SHA1withRSA_512_1024 1 true + * @run main/othervm CPBuilder intermediate_SHA1withRSA_512_512 1 true + * @run main/othervm CPBuilder intermediate_MD2withRSA_1024_1024 1 false + * @run main/othervm CPBuilder intermediate_MD2withRSA_1024_512 1 false + * @run main/othervm CPBuilder endentiry_SHA1withRSA_1024_1024 2 true + * @run main/othervm CPBuilder endentiry_SHA1withRSA_1024_512 2 true + * @run main/othervm CPBuilder endentiry_SHA1withRSA_512_1024 2 true + * @run main/othervm CPBuilder endentiry_SHA1withRSA_512_512 2 true + * @run main/othervm CPBuilder endentiry_MD2withRSA_1024_1024 2 false + * @run main/othervm CPBuilder endentiry_MD2withRSA_1024_512 2 false + * + * @author Xuelei Fan + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; +import sun.security.util.DerInputStream; + +public class CPBuilder { + + // SHA1withRSA 1024 + static String trustAnchor_SHA1withRSA_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH\n" + + "E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd\n" + + "rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID\n" + + "AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME\n" + + "QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + + "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z\n" + + "Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+\n" + + "UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc\n" + + "tas=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 + static String trustAnchor_SHA1withRSA_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB\n" + + "BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv\n" + + "7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU\n" + + "g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ\n" + + "5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b\n" + + "FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia\n" + + "U5r+8B9nzx+j2Zh3kw==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String intermediate_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDhaFw0yOTA0MjMwMTExNDha\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADgYEAHze3wAcIe84zNOoN\n" + + "P8l9EmlVVoU30z3LB3hxq3m/dC/4gE5Z9Z8EG1wJw4qaxlTZ4dif12nbTTdofVhb\n" + + "Bd4syjo6fcUA4q7sfg9TFpoHQ+Ap7PgjK99moMKdMy50Xy8s6FPvaVkF89s66Z6y\n" + + "e4q7TSwe6QevGOZaL5N/iy2XGEs=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String intermediate_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADQQCYNmdkONfuk07XjRze\n" + + "WQyq2cfdae4uIdyUfa2rpgYMtSXuQW3/XrQGiz4G6WBXA2wo7folOOpAKYgvHPrm\n" + + "w6Dd\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String intermediate_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDDCCAXWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAE2VOlw5ySLT3gUzKCYEga4QPaSrf6lHHPi2g48LscEY\n" + + "h9qQXh4nuIVugReBIEf6N49RdT+M2cgRJo4sZ3ukYLGQzxNuttL5nPSuuvrAR1oG\n" + + "LUyzOWcUpKHbVHi6zlTt79RvTKZvLcduLutmtPtLJcM9PdiAI1wEooSgxTwZtB/Z\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String intermediate_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIByzCCAXWgAwIBAgIBBTANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAUg4Kwd47hdNQBp8grZsRJ5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA0EAoCf0Zu559qcB4xPpzqkVsYiyW49S4Yc0mmQXb1yoQgLx\n" + + "O+DCkjG5d14+t1MsnkhB2izoQUMxQ3vDc1YnA/tEpw==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String intermediate_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADgYEAPtEjwbWuC5kc4DPc\n" + + "Ttf/wdbD8ZCdAWzcc3XF9q1TlvwVMNk6mbfM05y6ZVsztKTkwZ4EcvFu/yIqw1EB\n" + + "E1zlXQCaWXT3/ZMbqYZV4+mx+RUl8spUCb1tda25jnTg3mTOzB1iztm4gy903EMd\n" + + "m8omKDKeCgcw5dR4ITQYvyxe1as=\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String intermediate_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADQQBHok1v6xymtpB7N9xy\n" + + "0OmDT27uhmzlP0eOzJvXVxj3Oi9TLQJgCUJ9122MzfRAs1E1uJTtvuu+UmI80NQx\n" + + "KQdp\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String endentiry_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNzCCAaCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG\n" + + "9w0BAQUFAAOBgQAOfIeasDg91CR3jGfuAEVKwncM1OPFmniAUcdPm74cCAyJ90Me\n" + + "dhUElWPGoAuXGfiyZlOlGUYWqEroe/dnkmnotJjLWR+MA4ZyX3O1YI8T4W3deWcC\n" + + "J4WMCF7mp17SaYYKX9F0AxwNJFpUkbB41IkTxPr0MmzB1871/pbY8dLAvA==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String endentiry_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB9jCCAaCgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG\n" + + "9w0BAQUFAANBADV6X+ea0ftEKXy7yKNAbdIp35893T6AVwbdclomPkeOs86OtoTG\n" + + "1BIzWSK9QE7W6Wbf63e2RdcqoLK+DxsuwUg=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String endentiry_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB8zCCAVygAwIBAgIBBDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3\n" + + "DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo\n" + + "uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE\n" + + "AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU\n" + + "31g/ZkU6aXFAJVKhrrv0ebfAgeYwDQYJKoZIhvcNAQEFBQADgYEAUyW8PrEdbzLu\n" + + "B+h6UemBOJ024rYq90hJE/5wUEKPvxZ9vPEUgl+io6cGhL3cLfxfh6z5xtEGp4Tb\n" + + "NB0Ye3Qi01FBiNDY8s3rQRrmel6VysU8u+0Oi2jmQY6vZXn/zXN5rrTLITCaSicG\n" + + "dOMv1xLM83Ee432WWlDwKOUxhzDGpWc=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String endentiry_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBsjCCAVygAwIBAgIBBTANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3\n" + + "DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo\n" + + "uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE\n" + + "AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU\n" + + "N0CHiTYPtjyvpP2a6y6mhsZ6U40wDQYJKoZIhvcNAQEFBQADQQBG4grtrVEHick0\n" + + "z/6Lcl/MGyHT0c8KTXE0AMVXG1NRjAicAmYno/yDaJ9OmfymObKZKV9fF7yCW/N/\n" + + "TMU6m7N0\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String endentiry_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNzCCAaCgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG\n" + + "9w0BAQIFAAOBgQBxKsFf8NNQcXjDoKJJSG4Rk6ikcrhiGYuUI32+XHvs6hnav1Zc\n" + + "aJUpy7J4gMj/MnysMh/4AF9+m6zEEjuisXKUbYZhgtJxz+ukGSo163mJ8QJiAlRb\n" + + "Iwsy81r08mlSCR6jx2YhDAUxJIPC92R5Vb4CEutB7tWTwwz7vIHq330erA==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String endentiry_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB9jCCAaCgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG\n" + + "9w0BAQIFAANBAIX63Ypi9P71RnC/pcMbhD+wekRFsTzU593X3MC7tyBJtEXwvAZG\n" + + "iMxXF5A+ohlr7/CrkV7ZTL8PLxnJdY5Y8rQ=\n" + + "-----END CERTIFICATE-----"; + + static HashMap certmap = new HashMap(); + static { + certmap.put("trustAnchor_SHA1withRSA_1024", + trustAnchor_SHA1withRSA_1024); + certmap.put("trustAnchor_SHA1withRSA_512", + trustAnchor_SHA1withRSA_512); + certmap.put("intermediate_SHA1withRSA_1024_1024", + intermediate_SHA1withRSA_1024_1024); + certmap.put("intermediate_SHA1withRSA_1024_512", + intermediate_SHA1withRSA_1024_512); + certmap.put("intermediate_SHA1withRSA_512_1024", + intermediate_SHA1withRSA_512_1024); + certmap.put("intermediate_SHA1withRSA_512_512", + intermediate_SHA1withRSA_512_512); + certmap.put("intermediate_MD2withRSA_1024_1024", + intermediate_MD2withRSA_1024_1024); + certmap.put("intermediate_MD2withRSA_1024_512", + intermediate_MD2withRSA_1024_512); + certmap.put("endentiry_SHA1withRSA_1024_1024", + endentiry_SHA1withRSA_1024_1024); + certmap.put("endentiry_SHA1withRSA_1024_512", + endentiry_SHA1withRSA_1024_512); + certmap.put("endentiry_SHA1withRSA_512_1024", + endentiry_SHA1withRSA_512_1024); + certmap.put("endentiry_SHA1withRSA_512_512", + endentiry_SHA1withRSA_512_512); + certmap.put("endentiry_MD2withRSA_1024_1024", + endentiry_MD2withRSA_1024_1024); + certmap.put("endentiry_MD2withRSA_1024_512", + endentiry_MD2withRSA_1024_512); + } + + private static Set generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + HashSet anchors = new HashSet(); + + ByteArrayInputStream is = + new ByteArrayInputStream(trustAnchor_SHA1withRSA_1024.getBytes()); + Certificate cert = cf.generateCertificate(is); + TrustAnchor anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + is = new ByteArrayInputStream(trustAnchor_SHA1withRSA_512.getBytes()); + cert = cf.generateCertificate(is); + anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + return anchors; + } + + private static CertStore generateCertificateStore() throws Exception { + Collection entries = new HashSet(); + + // generate certificate from certificate string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + for (String key : certmap.keySet()) { + String certStr = certmap.get(key); + ByteArrayInputStream is = + new ByteArrayInputStream(certStr.getBytes());; + Certificate cert = cf.generateCertificate(is); + entries.add(cert); + } + + return CertStore.getInstance("Collection", + new CollectionCertStoreParameters(entries)); + } + + private static X509CertSelector generateSelector(String name) + throws Exception { + X509CertSelector selector = new X509CertSelector(); + + String certStr = certmap.get(name); + if (certStr == null) { + return null; + } + + // generate certificate from certificate string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream is = new ByteArrayInputStream(certStr.getBytes()); + X509Certificate target = (X509Certificate)cf.generateCertificate(is); + + selector.setCertificate(target); + + return selector; + } + + private static boolean match(String name, Certificate cert) + throws Exception { + X509CertSelector selector = new X509CertSelector(); + + String certStr = certmap.get(name); + if (certStr == null) { + return false; + } + + // generate certificate from certificate string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream is = new ByteArrayInputStream(certStr.getBytes()); + X509Certificate target = (X509Certificate)cf.generateCertificate(is); + + return target.equals(cert); + } + + public static void main(String args[]) throws Exception { + + CertPathBuilder builder = CertPathBuilder.getInstance("PKIX"); + + X509CertSelector selector = generateSelector(args[0]); + if (selector == null) { + // no target certificate, ignore it + return; + } + + Set anchors = generateTrustAnchors(); + CertStore certs = generateCertificateStore(); + + PKIXBuilderParameters params = + new PKIXBuilderParameters(anchors, selector); + params.addCertStore(certs); + params.setRevocationEnabled(false); + params.setDate(new Date(109, 9, 1)); // 2009-09-01 + + boolean success = Boolean.valueOf(args[2]); + try { + PKIXCertPathBuilderResult result = + (PKIXCertPathBuilderResult)builder.build(params); + if (!success) { + throw new Exception("expected algorithm disabled exception"); + } + + int length = Integer.parseInt(args[1]); + List path = + result.getCertPath().getCertificates(); + if (length != path.size()) { + throw new Exception("unexpected certification path length"); + } + + if (!path.isEmpty()) { // the target is not a trust anchor + if (!match(args[0], path.get(0))) { + throw new Exception("unexpected certificate"); + } + } + } catch (CertPathBuilderException cpbe) { + if (success) { + throw new Exception("unexpected exception"); + } else { + System.out.println("Get the expected exception " + cpbe); + } + } + } + +} diff --git a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java new file mode 100644 index 00000000000..bb0e886133e --- /dev/null +++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java @@ -0,0 +1,363 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * + * @bug 6861062 + * @summary Disable MD2 support + * + * @author Xuelei Fan + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; + +public class CPValidatorEndEntity { + + // SHA1withRSA 1024 + static String trustAnchor_SHA1withRSA_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH\n" + + "E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd\n" + + "rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID\n" + + "AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME\n" + + "QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + + "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z\n" + + "Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+\n" + + "UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc\n" + + "tas=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 + static String trustAnchor_SHA1withRSA_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB\n" + + "BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv\n" + + "7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU\n" + + "g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ\n" + + "5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b\n" + + "FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia\n" + + "U5r+8B9nzx+j2Zh3kw==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String intermediate_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDhaFw0yOTA0MjMwMTExNDha\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADgYEAHze3wAcIe84zNOoN\n" + + "P8l9EmlVVoU30z3LB3hxq3m/dC/4gE5Z9Z8EG1wJw4qaxlTZ4dif12nbTTdofVhb\n" + + "Bd4syjo6fcUA4q7sfg9TFpoHQ+Ap7PgjK99moMKdMy50Xy8s6FPvaVkF89s66Z6y\n" + + "e4q7TSwe6QevGOZaL5N/iy2XGEs=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String intermediate_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADQQCYNmdkONfuk07XjRze\n" + + "WQyq2cfdae4uIdyUfa2rpgYMtSXuQW3/XrQGiz4G6WBXA2wo7folOOpAKYgvHPrm\n" + + "w6Dd\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String intermediate_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDDCCAXWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAE2VOlw5ySLT3gUzKCYEga4QPaSrf6lHHPi2g48LscEY\n" + + "h9qQXh4nuIVugReBIEf6N49RdT+M2cgRJo4sZ3ukYLGQzxNuttL5nPSuuvrAR1oG\n" + + "LUyzOWcUpKHbVHi6zlTt79RvTKZvLcduLutmtPtLJcM9PdiAI1wEooSgxTwZtB/Z\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String intermediate_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIByzCCAXWgAwIBAgIBBTANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAUg4Kwd47hdNQBp8grZsRJ5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA0EAoCf0Zu559qcB4xPpzqkVsYiyW49S4Yc0mmQXb1yoQgLx\n" + + "O+DCkjG5d14+t1MsnkhB2izoQUMxQ3vDc1YnA/tEpw==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String intermediate_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADgYEAPtEjwbWuC5kc4DPc\n" + + "Ttf/wdbD8ZCdAWzcc3XF9q1TlvwVMNk6mbfM05y6ZVsztKTkwZ4EcvFu/yIqw1EB\n" + + "E1zlXQCaWXT3/ZMbqYZV4+mx+RUl8spUCb1tda25jnTg3mTOzB1iztm4gy903EMd\n" + + "m8omKDKeCgcw5dR4ITQYvyxe1as=\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String intermediate_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADQQBHok1v6xymtpB7N9xy\n" + + "0OmDT27uhmzlP0eOzJvXVxj3Oi9TLQJgCUJ9122MzfRAs1E1uJTtvuu+UmI80NQx\n" + + "KQdp\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String endentiry_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNzCCAaCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG\n" + + "9w0BAQUFAAOBgQAOfIeasDg91CR3jGfuAEVKwncM1OPFmniAUcdPm74cCAyJ90Me\n" + + "dhUElWPGoAuXGfiyZlOlGUYWqEroe/dnkmnotJjLWR+MA4ZyX3O1YI8T4W3deWcC\n" + + "J4WMCF7mp17SaYYKX9F0AxwNJFpUkbB41IkTxPr0MmzB1871/pbY8dLAvA==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String endentiry_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB9jCCAaCgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG\n" + + "9w0BAQUFAANBADV6X+ea0ftEKXy7yKNAbdIp35893T6AVwbdclomPkeOs86OtoTG\n" + + "1BIzWSK9QE7W6Wbf63e2RdcqoLK+DxsuwUg=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String endentiry_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB8zCCAVygAwIBAgIBBDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3\n" + + "DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo\n" + + "uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE\n" + + "AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU\n" + + "31g/ZkU6aXFAJVKhrrv0ebfAgeYwDQYJKoZIhvcNAQEFBQADgYEAUyW8PrEdbzLu\n" + + "B+h6UemBOJ024rYq90hJE/5wUEKPvxZ9vPEUgl+io6cGhL3cLfxfh6z5xtEGp4Tb\n" + + "NB0Ye3Qi01FBiNDY8s3rQRrmel6VysU8u+0Oi2jmQY6vZXn/zXN5rrTLITCaSicG\n" + + "dOMv1xLM83Ee432WWlDwKOUxhzDGpWc=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String endentiry_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBsjCCAVygAwIBAgIBBTANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3\n" + + "DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo\n" + + "uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE\n" + + "AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU\n" + + "N0CHiTYPtjyvpP2a6y6mhsZ6U40wDQYJKoZIhvcNAQEFBQADQQBG4grtrVEHick0\n" + + "z/6Lcl/MGyHT0c8KTXE0AMVXG1NRjAicAmYno/yDaJ9OmfymObKZKV9fF7yCW/N/\n" + + "TMU6m7N0\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String endentiry_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNzCCAaCgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG\n" + + "9w0BAQIFAAOBgQBxKsFf8NNQcXjDoKJJSG4Rk6ikcrhiGYuUI32+XHvs6hnav1Zc\n" + + "aJUpy7J4gMj/MnysMh/4AF9+m6zEEjuisXKUbYZhgtJxz+ukGSo163mJ8QJiAlRb\n" + + "Iwsy81r08mlSCR6jx2YhDAUxJIPC92R5Vb4CEutB7tWTwwz7vIHq330erA==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String endentiry_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB9jCCAaCgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG\n" + + "9w0BAQIFAANBAIX63Ypi9P71RnC/pcMbhD+wekRFsTzU593X3MC7tyBJtEXwvAZG\n" + + "iMxXF5A+ohlr7/CrkV7ZTL8PLxnJdY5Y8rQ=\n" + + "-----END CERTIFICATE-----"; + + private static CertPath generateCertificatePath(String castr, + String eestr) throws CertificateException { + // generate certificate from cert strings + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is; + + is = new ByteArrayInputStream(castr.getBytes()); + Certificate cacert = cf.generateCertificate(is); + + is = new ByteArrayInputStream(eestr.getBytes()); + Certificate eecert = cf.generateCertificate(is); + + // generate certification path + List list = Arrays.asList(new Certificate[] { + eecert, cacert}); + + return cf.generateCertPath(list); + } + + private static Set generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + HashSet anchors = new HashSet(); + + ByteArrayInputStream is = + new ByteArrayInputStream(trustAnchor_SHA1withRSA_1024.getBytes()); + Certificate cert = cf.generateCertificate(is); + TrustAnchor anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + is = new ByteArrayInputStream(trustAnchor_SHA1withRSA_512.getBytes()); + cert = cf.generateCertificate(is); + anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + return anchors; + } + + public static void main(String args[]) throws Exception { + try { + validate(endentiry_SHA1withRSA_1024_1024, + intermediate_SHA1withRSA_1024_1024); + validate(endentiry_SHA1withRSA_1024_512, + intermediate_SHA1withRSA_512_1024); + validate(endentiry_SHA1withRSA_512_1024, + intermediate_SHA1withRSA_1024_1024); + validate(endentiry_SHA1withRSA_512_512, + intermediate_SHA1withRSA_512_1024); + } catch (CertPathValidatorException cpve) { + throw new Exception( + "unexpect exception, it is valid cert", cpve); + } + + try { + validate(endentiry_MD2withRSA_1024_1024, + intermediate_SHA1withRSA_1024_1024); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + + try { + validate(endentiry_MD2withRSA_1024_512, + intermediate_SHA1withRSA_512_1024); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + } + + private static void validate(String eecert, String cacert) + throws CertPathValidatorException, Exception { + + CertPath path = generateCertificatePath(cacert, eecert); + Set anchors = generateTrustAnchors(); + + PKIXParameters params = new PKIXParameters(anchors); + + // disable certificate revocation checking + params.setRevocationEnabled(false); + + // set the validation time + params.setDate(new Date(109, 9, 1)); // 2009-09-01 + + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + + validator.validate(path, params); + } + +} diff --git a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java new file mode 100644 index 00000000000..ee450f9c8a0 --- /dev/null +++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java @@ -0,0 +1,256 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * + * @bug 6861062 + * @summary Disable MD2 support + * + * @author Xuelei Fan + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; + +public class CPValidatorIntermediate { + + // SHA1withRSA 1024 + static String trustAnchor_SHA1withRSA_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH\n" + + "E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd\n" + + "rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID\n" + + "AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME\n" + + "QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + + "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z\n" + + "Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+\n" + + "UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc\n" + + "tas=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 + static String trustAnchor_SHA1withRSA_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB\n" + + "BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv\n" + + "7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU\n" + + "g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ\n" + + "5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b\n" + + "FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia\n" + + "U5r+8B9nzx+j2Zh3kw==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String intermediate_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDhaFw0yOTA0MjMwMTExNDha\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADgYEAHze3wAcIe84zNOoN\n" + + "P8l9EmlVVoU30z3LB3hxq3m/dC/4gE5Z9Z8EG1wJw4qaxlTZ4dif12nbTTdofVhb\n" + + "Bd4syjo6fcUA4q7sfg9TFpoHQ+Ap7PgjK99moMKdMy50Xy8s6FPvaVkF89s66Z6y\n" + + "e4q7TSwe6QevGOZaL5N/iy2XGEs=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String intermediate_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADQQCYNmdkONfuk07XjRze\n" + + "WQyq2cfdae4uIdyUfa2rpgYMtSXuQW3/XrQGiz4G6WBXA2wo7folOOpAKYgvHPrm\n" + + "w6Dd\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String intermediate_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDDCCAXWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAE2VOlw5ySLT3gUzKCYEga4QPaSrf6lHHPi2g48LscEY\n" + + "h9qQXh4nuIVugReBIEf6N49RdT+M2cgRJo4sZ3ukYLGQzxNuttL5nPSuuvrAR1oG\n" + + "LUyzOWcUpKHbVHi6zlTt79RvTKZvLcduLutmtPtLJcM9PdiAI1wEooSgxTwZtB/Z\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String intermediate_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIByzCCAXWgAwIBAgIBBTANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAUg4Kwd47hdNQBp8grZsRJ5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA0EAoCf0Zu559qcB4xPpzqkVsYiyW49S4Yc0mmQXb1yoQgLx\n" + + "O+DCkjG5d14+t1MsnkhB2izoQUMxQ3vDc1YnA/tEpw==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String intermediate_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADgYEAPtEjwbWuC5kc4DPc\n" + + "Ttf/wdbD8ZCdAWzcc3XF9q1TlvwVMNk6mbfM05y6ZVsztKTkwZ4EcvFu/yIqw1EB\n" + + "E1zlXQCaWXT3/ZMbqYZV4+mx+RUl8spUCb1tda25jnTg3mTOzB1iztm4gy903EMd\n" + + "m8omKDKeCgcw5dR4ITQYvyxe1as=\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String intermediate_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADQQBHok1v6xymtpB7N9xy\n" + + "0OmDT27uhmzlP0eOzJvXVxj3Oi9TLQJgCUJ9122MzfRAs1E1uJTtvuu+UmI80NQx\n" + + "KQdp\n" + + "-----END CERTIFICATE-----"; + + private static CertPath generateCertificatePath(String certStr) + throws CertificateException { + // generate certificate from cert strings + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is; + + is = new ByteArrayInputStream(certStr.getBytes()); + Certificate cert = cf.generateCertificate(is); + + // generate certification path + List list = Arrays.asList(new Certificate[] {cert}); + + return cf.generateCertPath(list); + } + + private static Set generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + HashSet anchors = new HashSet(); + + ByteArrayInputStream is = + new ByteArrayInputStream(trustAnchor_SHA1withRSA_1024.getBytes()); + Certificate cert = cf.generateCertificate(is); + TrustAnchor anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + is = new ByteArrayInputStream(trustAnchor_SHA1withRSA_512.getBytes()); + cert = cf.generateCertificate(is); + anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + return anchors; + } + + public static void main(String args[]) throws Exception { + try { + validate(intermediate_SHA1withRSA_1024_1024); + validate(intermediate_SHA1withRSA_1024_512); + validate(intermediate_SHA1withRSA_512_1024); + validate(intermediate_SHA1withRSA_512_512); + } catch (CertPathValidatorException cpve) { + throw new Exception( + "unexpect exception, it is valid cert", cpve); + } + + try { + validate(intermediate_MD2withRSA_1024_1024); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + + try { + validate(intermediate_MD2withRSA_1024_512); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + } + + private static void validate(String intermediate) + throws CertPathValidatorException, Exception { + + CertPath path = generateCertificatePath(intermediate); + Set anchors = generateTrustAnchors(); + + PKIXParameters params = new PKIXParameters(anchors); + + // disable certificate revocation checking + params.setRevocationEnabled(false); + + // set the validation time + params.setDate(new Date(109, 9, 1)); // 2009-09-01 + + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + + validator.validate(path, params); + } + +} diff --git a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java new file mode 100644 index 00000000000..1aeac579e30 --- /dev/null +++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java @@ -0,0 +1,169 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * + * @bug 6861062 + * @summary Disable MD2 support + * + * @author Xuelei Fan + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; + +public class CPValidatorTrustAnchor { + + static String selfSignedCertStr = null; + + // SHA1withRSA 1024 + static String trustAnchor_SHA1withRSA_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH\n" + + "E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd\n" + + "rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID\n" + + "AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME\n" + + "QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + + "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z\n" + + "Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+\n" + + "UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc\n" + + "tas=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 + static String trustAnchor_SHA1withRSA_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB\n" + + "BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv\n" + + "7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU\n" + + "g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ\n" + + "5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b\n" + + "FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia\n" + + "U5r+8B9nzx+j2Zh3kw==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 2048 + static String trustAnchor_MD2withRSA_2048 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIDQzCCAiugAwIBAgIBADANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDdaFw0zMDA3MTcwMTExNDda\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIIBIjANBgkqhkiG9w0B\n" + + "AQEFAAOCAQ8AMIIBCgKCAQEArF5pINc5s+aUlmdYlxtAQ3V4TXFnP/XOYHxjfLuX\n" + + "eKO/kh78LMvbDisTPQ2yo9YEawwwbUU40xcuzgi0axXgKveHXYdUmTr0hEapq3rv\n" + + "g/q2EbOjyXvq4qK2RDoVCN8R3wXiytnY2OFALTx6zc2tW4imJ20svdNVtWhv2syj\n" + + "ZTmmRXAeFUbD4qKWAFij0I6pnSgVssvWzeyJUNemym+oiYyaSd7n5j1RNAqUKioo\n" + + "K/T0FOOiuPGMqottgx5YRHa6yapCP5QVWRQ+WBIYJY3Wyq7N+Es20LT6761Pk3to\n" + + "EFCzM7+zqT/c+pC079HOKXz+m2us+HKp5BKWNnbvgaYPOQIDAQABo4GJMIGGMB0G\n" + + "A1UdDgQWBBSrSukJf+mO5LTRasAGD9RRs7SASTBHBgNVHSMEQDA+gBSrSukJf+mO\n" + + "5LTRasAGD9RRs7SASaEjpCEwHzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1w\n" + + "bGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEC\n" + + "BQADggEBAHvsv+DqMJeIW/D+ltkhw37OdMzkMPp4E6Hbp03O3GZ5LfNGczHCb2uL\n" + + "sr5T7e/jaBFn6QfmqbOAYAHJSNq2bNNtTbatnHBLuVx13cfxmwk89Cg/tFeoUdcf\n" + + "m5hzurB6Ub6SsYMOxZHUYp/KxM9x9a7llC1bK3SKXwd4rVDlXh8DOBvdQNr5Q3yq\n" + + "JjY86bSXO14VzNxL/1rqHiszQdPyR/28SBsQVYSi0Zeyc4Yy1ui/cXu1+PWYw3YZ\n" + + "QUPHTnkVdPGwRiUqeZIcps+q+ePlQQmDu5qiLD6d8gsyGyY/RvCHWKO5Y9DuX9hs\n" + + "he/AhCWQx+TQYGLu0liQqLkGZydyRnA=\n" + + "-----END CERTIFICATE-----"; + + private static CertPath generateCertificatePath() + throws CertificateException { + // generate certificate from cert strings + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is; + + is = new ByteArrayInputStream(selfSignedCertStr.getBytes()); + Certificate selfSignedCert = cf.generateCertificate(is); + + // generate certification path + List list = Arrays.asList(new Certificate[] { + selfSignedCert}); + + return cf.generateCertPath(list); + } + + private static Set generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is = + new ByteArrayInputStream(selfSignedCertStr.getBytes()); + Certificate selfSignedCert = cf.generateCertificate(is); + + // generate a trust anchor + TrustAnchor anchor = + new TrustAnchor((X509Certificate)selfSignedCert, null); + + return Collections.singleton(anchor); + } + + public static void main(String args[]) throws Exception { + try { + validate(trustAnchor_SHA1withRSA_1024); + validate(trustAnchor_SHA1withRSA_512); + } catch (CertPathValidatorException cpve) { + throw new Exception( + "unexpect exception, it is valid cert", cpve); + } + + try { + validate(trustAnchor_MD2withRSA_2048); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + } + + private static void validate(String trustAnchor) + throws CertPathValidatorException, Exception { + selfSignedCertStr = trustAnchor; + + CertPath path = generateCertificatePath(); + Set anchors = generateTrustAnchors(); + + PKIXParameters params = new PKIXParameters(anchors); + + // disable certificate revocation checking + params.setRevocationEnabled(false); + + // set the validation time + params.setDate(new Date(109, 9, 1)); // 2009-09-01 + + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + + validator.validate(path, params); + } + +} diff --git a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/README b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/README new file mode 100644 index 00000000000..6577db95210 --- /dev/null +++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/README @@ -0,0 +1,640 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + Certificates and CRLs + +Here lists the Certificates, which was generated by generate.sh, used in the +test cases. + +The generate.sh depends on openssl, and it should be run under ksh. The +script will create many directories and files, please run it in a +directory outside of JDK workspace. + +1. root certifiate and key (SHA1withRSA 1024, root_cert_sha1_1024.pem) +-----BEGIN CERTIFICATE----- +MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa +MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH +E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd +rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID +AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME +QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO +BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw +DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z +Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+ +UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc +tas= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,DF5249E009A0FD79 + +rc316yLipp/vH0i6rhEbEwZpZ+HfKIXnnp/bIIZv2+4lyGUDWrxN0Hk0TcSgWEKm +dRGI2fsyWjTgaiHwwmusofXPAjB3s0I2rUUAHXk8/sEuiLLTICx2UAL8k6R33CSQ +NKR8t+TluBW3Us71vibWauuMHa5860KiiLWdhkQVLin7m/JBGLtz0zQ0/lZ8CgEm +p7eDupPi8FBClCyVewdpmKjgI2KPI4fVIZLMzLeGcWLaOQPN1ERcFWQ1CS/qjfMb +F4rtpZ+AzCqP75XPhitT2CnZgaVDxHBtAZQVPuKONMdijKphjqiT/Sd86Gx6OEVE +EwwmQya2Q/5aCuH96S00mj00oeIZ7ZtUcVQcch+saJy4vpuxK8pFcEDKmgsvL9+8 +Hho9RUXVUKRH67uA1NjQSK5+syEIj5sJCDcxOda4QGXeIq9ygaZswxF3nfvffrsa +S6IVBXrx0G+Ascu29SHoI+zi3feQszQJIzijHoTTq6FacLHUWzfVuaYa47uaj5qa +VYsMVCzi1eX486o7YKPKWiclNczQN86v5n9+c9uggXY12wSOmnf6BB1Ds+oL8JlU +IZa67lAyg6G9joAb9rTXN2EE5OTArcFuImK8GHse/3wkIPMglBNnfwpvjC1U+vQm +F7iXp+OxnZ5d9sBcrTBEZ9BDlTVlpiZI7EeS1oC8x6DDTdbJR/40Y3wJIDMI9q9T +O5EnyXqbmQziO0Tgal43w6mMTUnhG34kqovwxy03mAOZb3yz/RgWlez9wQmPseiI +2p2fQIjCPbGFNJt3rdyXOW/BRCii0970HEZeov/TVV/A0vUVajNAjA== +-----END RSA PRIVATE KEY----- + +2. root certifiate and key (SHA1withRSA 512, root_cert_sha1_512.pem) +-----BEGIN CERTIFICATE----- +MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa +MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB +BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv +7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU +g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ +5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G +A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b +FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia +U5r+8B9nzx+j2Zh3kw== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,B8BDE38F08C6BB76 + +eJzx2oZE0UXxWpzssSWtKBOCbm3ZXR6iBKX8iKoDUB5SzzmKr+XzxI7kyv92y0pe +rNTuuCWpBsLdlz7h8Ipn4pBDYswGU5F9MQOEgIYx60OvGhZODHGRzJ05FXTeCmmu +LLp6lGW4SWALcd8g/gJUn1/vp7f1VzQ7RwXWBn4/b34RRYtwr3E6nl4Hc2tEI1in +OL+lCdAAyxjGK7KYFHJQK+1E8tYNrer3cejQDcNysGx4o0H123vfp3NtJ6U7LXyi +D21y3zmPueJos8LluJiLRsONcrcI3mIfpPBsO+Yl2EJtzS9V6Aaq/YdPkwPHH6Y5 +lazGMPXq/nffb12fWLL7m5aFb3FNLwWi/qwEynWCEv7Vl/6kLk+aHhjTnYkLvLNH +9maQFn6j0S3wqogRfW9BDbfC3fRHP6+8YjEEmQ0RTfE= +-----END RSA PRIVATE KEY----- + +3. root certifiate and key (MD2withRSA 2048, root_cert_md2_2048.pem) +-----BEGIN CERTIFICATE----- +MIIDQzCCAiugAwIBAgIBADANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDdaFw0zMDA3MTcwMTExNDda +MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEArF5pINc5s+aUlmdYlxtAQ3V4TXFnP/XOYHxjfLuX +eKO/kh78LMvbDisTPQ2yo9YEawwwbUU40xcuzgi0axXgKveHXYdUmTr0hEapq3rv +g/q2EbOjyXvq4qK2RDoVCN8R3wXiytnY2OFALTx6zc2tW4imJ20svdNVtWhv2syj +ZTmmRXAeFUbD4qKWAFij0I6pnSgVssvWzeyJUNemym+oiYyaSd7n5j1RNAqUKioo +K/T0FOOiuPGMqottgx5YRHa6yapCP5QVWRQ+WBIYJY3Wyq7N+Es20LT6761Pk3to +EFCzM7+zqT/c+pC079HOKXz+m2us+HKp5BKWNnbvgaYPOQIDAQABo4GJMIGGMB0G +A1UdDgQWBBSrSukJf+mO5LTRasAGD9RRs7SASTBHBgNVHSMEQDA+gBSrSukJf+mO +5LTRasAGD9RRs7SASaEjpCEwHzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1w +bGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEC +BQADggEBAHvsv+DqMJeIW/D+ltkhw37OdMzkMPp4E6Hbp03O3GZ5LfNGczHCb2uL +sr5T7e/jaBFn6QfmqbOAYAHJSNq2bNNtTbatnHBLuVx13cfxmwk89Cg/tFeoUdcf +m5hzurB6Ub6SsYMOxZHUYp/KxM9x9a7llC1bK3SKXwd4rVDlXh8DOBvdQNr5Q3yq +JjY86bSXO14VzNxL/1rqHiszQdPyR/28SBsQVYSi0Zeyc4Yy1ui/cXu1+PWYw3YZ +QUPHTnkVdPGwRiUqeZIcps+q+ePlQQmDu5qiLD6d8gsyGyY/RvCHWKO5Y9DuX9hs +he/AhCWQx+TQYGLu0liQqLkGZydyRnA= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,3910D329AD49ECFC + +6K0OU3Xrl2H6kz7x7EHXkM0/Wd6jXBBwWsaroUIGnbIMmljJXPfgcuDUu6f5Imk1 +ndoU0GWjxa1QNjteAQQtFoLDP8rienLs0b969OcAxB0EOffQFkEfsfXdyEIgdwkD +ETczwDIyd8Wj62ClydJES3jKB9Nc9kMIlsoZ+h24TyJeeRsHAtMrz+mlOHsUWDQ5 +FyYZelnx+fQ5maD3bura7xLiNl8CvgWz0wt2Wt4djdMGhQ3OWd0/GWweP+2xnL6n +5tDJ5On50+Z5T8Jhx62yg+wQiBKAYnYw6OX3skJwWknuAvYz3Z3e12DHFx6w5EAU +K7lg7fHMqHNirUkJOlYzgJ21ybV4uQmFRNQJwI9h6GVfdZWPEU+Ni42AlNgNYskF +K19dONNNt0Gwkcm2VOYzwYGDyaQW2YIGDk1fbZdVSu/h/lyOC/RmorGWroAbYsyB +/GUIilcLtQHPGI8XuojTS2/UWcKactpceN3UOnQkus3/smViEqqB/NQ/lcozgs0o +7ZG6H6to7w1yb5VR2d7B2bS7MNJt1AsOB5ydAMYIccdHDTI7CfRK6axQ70O/JPnJ +WLY2e41ig2uAWk/3fRb8L6d3keVcN7y4WnkXPbHhulqtxQo78iSQQAf7tDMBxWKx +C5LQW3CxLkHKp6g22SDxl2LjJyu5nDbtIh3Pq+BCoA25uqXC4rPoWwV7EWYv8Z+Y +E6dS98SEa+cDhpllvGzbTKgcP1VqtQbb9VT92UT1mFrklqRuQIxROeCe4wjp5TKo +D2losUDdzpqBHkBNo2I8qZkgybeCvWEq73my2+JG1AAIFFB1kzfBNaBDGiGSuUuS +5peV8156aaLg5pxdieoRJ3Y7eaWN1wH5CnRnafoB+lxSUsQO1a7y2LbpedrKjs+2 +AryPHQw7HLd8IQevmvd7BhJLdvlt+kXzWID/pUsSAYvI7aP4daQJuAt/kwmU27Gd +wqhV8Tjbb84vFGmqGHtb2YbKfUrsPUNOLBF+U4SDAgBhEyhINQZyRDcqqoywO5Dr +sV46nTEfwAgt88KFt2CEhiyvoJbtCj1iMJeAzuljwF4z4RzB1i3TK0MaJYID2rxB +E1vK9EZIssk/NeImN2YCbuqOhU58jtOwYh3ruS+mZQm1APvJF9N4tCCVQsjWC6zY +4eqs7T6VDFH4AaT7b3J3rTsEpWIDUfagetZs5kR9SiWJC7dU7r53gGg4avVyIIHD ++MYCS+auD9/nmVf4iYstVgJFMUJXC2EUOLi0r8KmDkCILl/K3X/W7QwFTnC07gLh +/9HjWFJ0R6cyODzvE8NGPMeuJGUT2F+mA1vaAC/PBGz+61AF0BjWTZ7x2sH+tSPP +/GVEaCgyzrKRX5XX+7DulTcmFj1JNfMmtbDaJa9WnwOI4qszBGrAcYeYTHXR6Yov +Ux/P6RStfa+UwSjo8i3nfdgLk+RXCpN0srMjSmiQx8d5R/kISqXKDtQfS5M6gsoh +ROz+6zZP8Gh8yakr1p4C6JUSiLDYP5qXzxr8bp+oxvpY7anEDAqx21HyExEAu+gy +IrNl75FWqV8BbKxoFfe9LqyDaryXXA8oy6F+4BT/zRrxp+dym9pbd+OZR423BIij +-----END RSA PRIVATE KEY----- + +4. subca certificate and key (SHA1withRSA 1024, root_cert_sha1_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICUDCCAbmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDhaFw0yOTA0MjMwMTExNDha +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8 +BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg +bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82 +AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl +UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw +HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADgYEAHze3wAcIe84zNOoN +P8l9EmlVVoU30z3LB3hxq3m/dC/4gE5Z9Z8EG1wJw4qaxlTZ4dif12nbTTdofVhb +Bd4syjo6fcUA4q7sfg9TFpoHQ+Ap7PgjK99moMKdMy50Xy8s6FPvaVkF89s66Z6y +e4q7TSwe6QevGOZaL5N/iy2XGEs= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0480E76FD259323B + +npiifBm1mHq1Z9QgAV5T35Xbnea9VnwqYQWNfRRKmpfYSdkQJ0few18YtnfZwh9e +LKCWx+lq1V4yDG4SbxXDq71Dyvx1vZY+w4h+6M1+6KGFG1VDBfN3e5aLgK8EG9pZ +yHZH7iB7HiQXH5q53jL6NUZn55C3XEk1sErpK7R1c0Y8Qp2TGiu+lck3K+zR9GiO +5aJMKbShReB0Nfy3JJNKRFSd95QMTTjbq6iIvhN8O02bo4I4I3HTyD8qyR7ViiHl +FmOukjwn4fjJvK0WYKYUjod8oEiMdR2nr73eOGZBAnEorDGQ8VnnCAleSv74is1k +W7M07UP7EJJq9hSZfeMqk5QivtWrqvWG1SWxpTowKTEAyTn7u5U13k0DiRcsg0WT +4mSMiLOhUNgIWcHElbTQPSVDcVznhNk0dWPDwKoUjp+orCuH+NvHKBAu+hnuip3e +Ji7WGrHXI7QxAr5qr5ogl5x4yH4drIbq9fUea3NTuGPuPyu9fWjOSDmqPRKRMJFR +UxxVFcyrW8iSBV5cvB7M1ADS40y6l4ryYmKjXbsOI4Ci8LJWJ4ZB61WQP7TvPQGS +mNFmTTB2dwbpimr4KjV9j2bA9x0jAsjlcQZ5j1GOeyYCEDGKDJw0XD/zI+j0dpVc +eu8YtuJGTyO1h+HiI3D9LrMuyUxxckvFHKe00+4xMz1hpqVo/kxe6gqf/9ES4M/h +6/NeTzeqyJF2rgxK6KJJdmaKVYI+bvAQ3cKl+RZmgOjx4eig58N5uthqFgU7rQ+e +GM9/y8C9WpPqITcJlY7I/7AkqvYDBwBsH/9mf4g9OUbC1Ah+MX8UIQ== +-----END RSA PRIVATE KEY----- + + +5. subca certificate and key (SHA1withRSA 1024, root_cert_sha1_512.pem signed) +-----BEGIN CERTIFICATE----- +MIICDzCCAbmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8 +BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg +bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82 +AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl +UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw +HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADQQCYNmdkONfuk07XjRze +WQyq2cfdae4uIdyUfa2rpgYMtSXuQW3/XrQGiz4G6WBXA2wo7folOOpAKYgvHPrm +w6Dd +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0480E76FD259323B + +npiifBm1mHq1Z9QgAV5T35Xbnea9VnwqYQWNfRRKmpfYSdkQJ0few18YtnfZwh9e +LKCWx+lq1V4yDG4SbxXDq71Dyvx1vZY+w4h+6M1+6KGFG1VDBfN3e5aLgK8EG9pZ +yHZH7iB7HiQXH5q53jL6NUZn55C3XEk1sErpK7R1c0Y8Qp2TGiu+lck3K+zR9GiO +5aJMKbShReB0Nfy3JJNKRFSd95QMTTjbq6iIvhN8O02bo4I4I3HTyD8qyR7ViiHl +FmOukjwn4fjJvK0WYKYUjod8oEiMdR2nr73eOGZBAnEorDGQ8VnnCAleSv74is1k +W7M07UP7EJJq9hSZfeMqk5QivtWrqvWG1SWxpTowKTEAyTn7u5U13k0DiRcsg0WT +4mSMiLOhUNgIWcHElbTQPSVDcVznhNk0dWPDwKoUjp+orCuH+NvHKBAu+hnuip3e +Ji7WGrHXI7QxAr5qr5ogl5x4yH4drIbq9fUea3NTuGPuPyu9fWjOSDmqPRKRMJFR +UxxVFcyrW8iSBV5cvB7M1ADS40y6l4ryYmKjXbsOI4Ci8LJWJ4ZB61WQP7TvPQGS +mNFmTTB2dwbpimr4KjV9j2bA9x0jAsjlcQZ5j1GOeyYCEDGKDJw0XD/zI+j0dpVc +eu8YtuJGTyO1h+HiI3D9LrMuyUxxckvFHKe00+4xMz1hpqVo/kxe6gqf/9ES4M/h +6/NeTzeqyJF2rgxK6KJJdmaKVYI+bvAQ3cKl+RZmgOjx4eig58N5uthqFgU7rQ+e +GM9/y8C9WpPqITcJlY7I/7AkqvYDBwBsH/9mf4g9OUbC1Ah+MX8UIQ== +-----END RSA PRIVATE KEY----- + + +6. subca certificate and key (SHA1withRSA 512, root_cert_sha1_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICDDCCAXWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV +lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA +AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw +PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD +VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G +CSqGSIb3DQEBBQUAA4GBAE2VOlw5ySLT3gUzKCYEga4QPaSrf6lHHPi2g48LscEY +h9qQXh4nuIVugReBIEf6N49RdT+M2cgRJo4sZ3ukYLGQzxNuttL5nPSuuvrAR1oG +LUyzOWcUpKHbVHi6zlTt79RvTKZvLcduLutmtPtLJcM9PdiAI1wEooSgxTwZtB/Z +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0A94F7EA4C89CA33 + +tfKdAZVSrpeS/hU4+mGYcGGx3nNqrE+CzDAfLadVuXz5ju5p9oFhLTZj99wK+uHn +prrWmDNOdYKRBJn7h40WV6zi4lR3JgnuYNxH8fxO3PI+HQ9IuvdoTyqUeXTP4Zj1 +BCnr1k1D2WGDXvnh+saq9qRpMKThjK/OF0YmDa07PI5NOBdMA3EmkNYfwib2GfBV +el4FVkfnPQkLGahTh3SC62TzPlnsAgirCeua7ZLPqN3fkZkYbXZd9op2D31n7cBP +zztg0ah8WF4gPOd/BBZeR9XDog5qm/wzyBj0F6ClHRPjpGYhAm2Vw66xOBlGFYI9 +lVmFQzrPcDNlFTybzhl5C6Qy4cPQh+QErDWxljVI52oYYmY/KRmUGGL7hEG8ZGOn +EUgFrEJyAY7w4wpBC5n9SotwyPXhwKQ1uCBq+1zElPw= +-----END RSA PRIVATE KEY----- + +7. subca certificate and key (SHA1withRSA 512, root_cert_sha1_512.pem signed) +-----BEGIN CERTIFICATE----- +MIIByzCCAXWgAwIBAgIBBTANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV +lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA +AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw +PoAUg4Kwd47hdNQBp8grZsRJ5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD +VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G +CSqGSIb3DQEBBQUAA0EAoCf0Zu559qcB4xPpzqkVsYiyW49S4Yc0mmQXb1yoQgLx +O+DCkjG5d14+t1MsnkhB2izoQUMxQ3vDc1YnA/tEpw== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0A94F7EA4C89CA33 + +tfKdAZVSrpeS/hU4+mGYcGGx3nNqrE+CzDAfLadVuXz5ju5p9oFhLTZj99wK+uHn +prrWmDNOdYKRBJn7h40WV6zi4lR3JgnuYNxH8fxO3PI+HQ9IuvdoTyqUeXTP4Zj1 +BCnr1k1D2WGDXvnh+saq9qRpMKThjK/OF0YmDa07PI5NOBdMA3EmkNYfwib2GfBV +el4FVkfnPQkLGahTh3SC62TzPlnsAgirCeua7ZLPqN3fkZkYbXZd9op2D31n7cBP +zztg0ah8WF4gPOd/BBZeR9XDog5qm/wzyBj0F6ClHRPjpGYhAm2Vw66xOBlGFYI9 +lVmFQzrPcDNlFTybzhl5C6Qy4cPQh+QErDWxljVI52oYYmY/KRmUGGL7hEG8ZGOn +EUgFrEJyAY7w4wpBC5n9SotwyPXhwKQ1uCBq+1zElPw= +-----END RSA PRIVATE KEY----- + +8. subca certificate and key (MD2withRSA 1024, root_cert_sha1_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICUDCCAbmgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8 +BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg +bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82 +AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl +UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw +HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADgYEAPtEjwbWuC5kc4DPc +Ttf/wdbD8ZCdAWzcc3XF9q1TlvwVMNk6mbfM05y6ZVsztKTkwZ4EcvFu/yIqw1EB +E1zlXQCaWXT3/ZMbqYZV4+mx+RUl8spUCb1tda25jnTg3mTOzB1iztm4gy903EMd +m8omKDKeCgcw5dR4ITQYvyxe1as= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0480E76FD259323B + +npiifBm1mHq1Z9QgAV5T35Xbnea9VnwqYQWNfRRKmpfYSdkQJ0few18YtnfZwh9e +LKCWx+lq1V4yDG4SbxXDq71Dyvx1vZY+w4h+6M1+6KGFG1VDBfN3e5aLgK8EG9pZ +yHZH7iB7HiQXH5q53jL6NUZn55C3XEk1sErpK7R1c0Y8Qp2TGiu+lck3K+zR9GiO +5aJMKbShReB0Nfy3JJNKRFSd95QMTTjbq6iIvhN8O02bo4I4I3HTyD8qyR7ViiHl +FmOukjwn4fjJvK0WYKYUjod8oEiMdR2nr73eOGZBAnEorDGQ8VnnCAleSv74is1k +W7M07UP7EJJq9hSZfeMqk5QivtWrqvWG1SWxpTowKTEAyTn7u5U13k0DiRcsg0WT +4mSMiLOhUNgIWcHElbTQPSVDcVznhNk0dWPDwKoUjp+orCuH+NvHKBAu+hnuip3e +Ji7WGrHXI7QxAr5qr5ogl5x4yH4drIbq9fUea3NTuGPuPyu9fWjOSDmqPRKRMJFR +UxxVFcyrW8iSBV5cvB7M1ADS40y6l4ryYmKjXbsOI4Ci8LJWJ4ZB61WQP7TvPQGS +mNFmTTB2dwbpimr4KjV9j2bA9x0jAsjlcQZ5j1GOeyYCEDGKDJw0XD/zI+j0dpVc +eu8YtuJGTyO1h+HiI3D9LrMuyUxxckvFHKe00+4xMz1hpqVo/kxe6gqf/9ES4M/h +6/NeTzeqyJF2rgxK6KJJdmaKVYI+bvAQ3cKl+RZmgOjx4eig58N5uthqFgU7rQ+e +GM9/y8C9WpPqITcJlY7I/7AkqvYDBwBsH/9mf4g9OUbC1Ah+MX8UIQ== +-----END RSA PRIVATE KEY----- + + +9. subca certificate and key (MD2withRSA 1024, root_cert_sha1_512.pem signed) +-----BEGIN CERTIFICATE----- +MIICDzCCAbmgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8 +BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg +bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82 +AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl +UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw +HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADQQBHok1v6xymtpB7N9xy +0OmDT27uhmzlP0eOzJvXVxj3Oi9TLQJgCUJ9122MzfRAs1E1uJTtvuu+UmI80NQx +KQdp +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0480E76FD259323B + +npiifBm1mHq1Z9QgAV5T35Xbnea9VnwqYQWNfRRKmpfYSdkQJ0few18YtnfZwh9e +LKCWx+lq1V4yDG4SbxXDq71Dyvx1vZY+w4h+6M1+6KGFG1VDBfN3e5aLgK8EG9pZ +yHZH7iB7HiQXH5q53jL6NUZn55C3XEk1sErpK7R1c0Y8Qp2TGiu+lck3K+zR9GiO +5aJMKbShReB0Nfy3JJNKRFSd95QMTTjbq6iIvhN8O02bo4I4I3HTyD8qyR7ViiHl +FmOukjwn4fjJvK0WYKYUjod8oEiMdR2nr73eOGZBAnEorDGQ8VnnCAleSv74is1k +W7M07UP7EJJq9hSZfeMqk5QivtWrqvWG1SWxpTowKTEAyTn7u5U13k0DiRcsg0WT +4mSMiLOhUNgIWcHElbTQPSVDcVznhNk0dWPDwKoUjp+orCuH+NvHKBAu+hnuip3e +Ji7WGrHXI7QxAr5qr5ogl5x4yH4drIbq9fUea3NTuGPuPyu9fWjOSDmqPRKRMJFR +UxxVFcyrW8iSBV5cvB7M1ADS40y6l4ryYmKjXbsOI4Ci8LJWJ4ZB61WQP7TvPQGS +mNFmTTB2dwbpimr4KjV9j2bA9x0jAsjlcQZ5j1GOeyYCEDGKDJw0XD/zI+j0dpVc +eu8YtuJGTyO1h+HiI3D9LrMuyUxxckvFHKe00+4xMz1hpqVo/kxe6gqf/9ES4M/h +6/NeTzeqyJF2rgxK6KJJdmaKVYI+bvAQ3cKl+RZmgOjx4eig58N5uthqFgU7rQ+e +GM9/y8C9WpPqITcJlY7I/7AkqvYDBwBsH/9mf4g9OUbC1Ah+MX8UIQ== +-----END RSA PRIVATE KEY----- + + +a. end entity certificate and key + (SHA1withRSA 1024, subca_cert_sha1_1024_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICNzCCAaCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt +vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v +z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6 +c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07 +OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG +9w0BAQUFAAOBgQAOfIeasDg91CR3jGfuAEVKwncM1OPFmniAUcdPm74cCAyJ90Me +dhUElWPGoAuXGfiyZlOlGUYWqEroe/dnkmnotJjLWR+MA4ZyX3O1YI8T4W3deWcC +J4WMCF7mp17SaYYKX9F0AxwNJFpUkbB41IkTxPr0MmzB1871/pbY8dLAvA== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,1FE5A37B770AF83D + +042bWtt4q0cB8pRuPUlMVncTP/WAz+mmPw3jXI3LFOBZeK6zFEDpI5M9c2JO+rqp +Za5UkYuIg69V7LngriqRynkRGGQp3xASMLr5NVbKHTE/Ol/iIuxKaCkumZmGXB/z +8bxQF5XN4tbKT4s3sWWmmKMicg6MHvySi3QVRG11PHRu/q7CEFPzJKRQ3fpaNcKD +NTBI5F6GP9ENa/eog4WGENjXS0v4Wa3IfaOhjKXrSxjLUqLH0C8g5WWg5IrXXtuI +pgyJ2kkE3Y/ChU7p7R42we6tBZqF5SiL5kFDn86DmHgCslTiZkIoE5i644sp03Sd +XkHyHu0VIeYp3nDwRA7S98837W4F6i1BnXA5f3EaE3rNGjsxK8zL2pvdCcDYbese +ETfba16HMzLXe1b4RSI3gwhlQ2MNKBwvskkQESf/Ew1DskBY0MCYFxo6hIp6LqMo +HAl5kvCwvuYL2jBdQhkKxU+Leu5Ei8Ie9XYNVy4yUeUAMnSUkVaEs/I8z+Mk8oYq +4QWqOc66XLcI13coDoxmv54kye3RjqdmZI8mg/3LCFotwceDuXyD43/vVhoTPEnp +CqXafV2pw4y95skMHmktI2qvSahaM4P6GGXl8HqmP3b+8V5mxMhNtVnuUha2kouw +DLNFUTg1cCLahM5SRolyA/XTGh7JOkJMYWPeJwN7l3K+lBtHHfj6DHtKEjUcyZFd ++Z55pDoAERumB6+BCnt6X2/0kEDV219RmsgxkGTWdFs+M7Y6EYYRtlinH4nqL6UD +eHWitYIatAHOvdHeNrbXN9L5P3tsUB4HzFa46WWtKqRtbCVTuPVZdw== +-----END RSA PRIVATE KEY----- + +b. end entity certificate and key + (SHA1withRSA 1024, subca_cert_sha1_512_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIIB9jCCAaCgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt +vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v +z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6 +c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07 +OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG +9w0BAQUFAANBADV6X+ea0ftEKXy7yKNAbdIp35893T6AVwbdclomPkeOs86OtoTG +1BIzWSK9QE7W6Wbf63e2RdcqoLK+DxsuwUg= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,1FE5A37B770AF83D + +042bWtt4q0cB8pRuPUlMVncTP/WAz+mmPw3jXI3LFOBZeK6zFEDpI5M9c2JO+rqp +Za5UkYuIg69V7LngriqRynkRGGQp3xASMLr5NVbKHTE/Ol/iIuxKaCkumZmGXB/z +8bxQF5XN4tbKT4s3sWWmmKMicg6MHvySi3QVRG11PHRu/q7CEFPzJKRQ3fpaNcKD +NTBI5F6GP9ENa/eog4WGENjXS0v4Wa3IfaOhjKXrSxjLUqLH0C8g5WWg5IrXXtuI +pgyJ2kkE3Y/ChU7p7R42we6tBZqF5SiL5kFDn86DmHgCslTiZkIoE5i644sp03Sd +XkHyHu0VIeYp3nDwRA7S98837W4F6i1BnXA5f3EaE3rNGjsxK8zL2pvdCcDYbese +ETfba16HMzLXe1b4RSI3gwhlQ2MNKBwvskkQESf/Ew1DskBY0MCYFxo6hIp6LqMo +HAl5kvCwvuYL2jBdQhkKxU+Leu5Ei8Ie9XYNVy4yUeUAMnSUkVaEs/I8z+Mk8oYq +4QWqOc66XLcI13coDoxmv54kye3RjqdmZI8mg/3LCFotwceDuXyD43/vVhoTPEnp +CqXafV2pw4y95skMHmktI2qvSahaM4P6GGXl8HqmP3b+8V5mxMhNtVnuUha2kouw +DLNFUTg1cCLahM5SRolyA/XTGh7JOkJMYWPeJwN7l3K+lBtHHfj6DHtKEjUcyZFd ++Z55pDoAERumB6+BCnt6X2/0kEDV219RmsgxkGTWdFs+M7Y6EYYRtlinH4nqL6UD +eHWitYIatAHOvdHeNrbXN9L5P3tsUB4HzFa46WWtKqRtbCVTuPVZdw== +-----END RSA PRIVATE KEY----- + +c. end entity certificate and key + (SHA1withRSA 512, subca_cert_sha1_1024_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIIB8zCCAVygAwIBAgIBBDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3 +DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo +uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE +AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU +31g/ZkU6aXFAJVKhrrv0ebfAgeYwDQYJKoZIhvcNAQEFBQADgYEAUyW8PrEdbzLu +B+h6UemBOJ024rYq90hJE/5wUEKPvxZ9vPEUgl+io6cGhL3cLfxfh6z5xtEGp4Tb +NB0Ye3Qi01FBiNDY8s3rQRrmel6VysU8u+0Oi2jmQY6vZXn/zXN5rrTLITCaSicG +dOMv1xLM83Ee432WWlDwKOUxhzDGpWc= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,153918982D82A26E + +5w5MNd16M1draSfIFAuWNfP3869l9y8vMI1kOcxqsxjeG6YfgKUyu6PEYlj1R7d1 +/+UwVs9RGm3V7AwV4G1Qpnd+jaMLpgPVMP12sHPnslBE4SQe9bAZ+X5i2/5uesHv +bF7OBMqsYW8+Kgsy1Ac0pBx/8yoFYdD3KYFnIP20kV2Xxy4PtQQ6tHJ33dGslTNU +qrcJsyUyYj6wORlb7huuP5Ua8f28Xs/KvnNJG0094kC1WHi3Raf4AoD/rvraVtCQ +5jrK9se8D6su+S3SEW0YndxivbNx3xJu2O72e7lS6yb5ht3U7xNSSWTffIlW1okI +zjscK0iv9S+x452mLIFUgkmriVJLFfjTMRCbhS1J6q9FXLDdre/2O18FO2TvwRIE +6Bwt2utfOAGccRHLsdgcXkv+ngCTCkuCnmh2XZWqmvA= +-----END RSA PRIVATE KEY----- + +d. end entity certificate and key + (SHA1withRSA 512, subca_cert_sha1_512_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIIBsjCCAVygAwIBAgIBBTANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3 +DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo +uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE +AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU +N0CHiTYPtjyvpP2a6y6mhsZ6U40wDQYJKoZIhvcNAQEFBQADQQBG4grtrVEHick0 +z/6Lcl/MGyHT0c8KTXE0AMVXG1NRjAicAmYno/yDaJ9OmfymObKZKV9fF7yCW/N/ +TMU6m7N0 +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,153918982D82A26E + +5w5MNd16M1draSfIFAuWNfP3869l9y8vMI1kOcxqsxjeG6YfgKUyu6PEYlj1R7d1 +/+UwVs9RGm3V7AwV4G1Qpnd+jaMLpgPVMP12sHPnslBE4SQe9bAZ+X5i2/5uesHv +bF7OBMqsYW8+Kgsy1Ac0pBx/8yoFYdD3KYFnIP20kV2Xxy4PtQQ6tHJ33dGslTNU +qrcJsyUyYj6wORlb7huuP5Ua8f28Xs/KvnNJG0094kC1WHi3Raf4AoD/rvraVtCQ +5jrK9se8D6su+S3SEW0YndxivbNx3xJu2O72e7lS6yb5ht3U7xNSSWTffIlW1okI +zjscK0iv9S+x452mLIFUgkmriVJLFfjTMRCbhS1J6q9FXLDdre/2O18FO2TvwRIE +6Bwt2utfOAGccRHLsdgcXkv+ngCTCkuCnmh2XZWqmvA= +-----END RSA PRIVATE KEY----- + +e. end entity certificate and key + (MD2withRSA 1024, subca_cert_sha1_1024_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICNzCCAaCgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt +vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v +z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6 +c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07 +OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG +9w0BAQIFAAOBgQBxKsFf8NNQcXjDoKJJSG4Rk6ikcrhiGYuUI32+XHvs6hnav1Zc +aJUpy7J4gMj/MnysMh/4AF9+m6zEEjuisXKUbYZhgtJxz+ukGSo163mJ8QJiAlRb +Iwsy81r08mlSCR6jx2YhDAUxJIPC92R5Vb4CEutB7tWTwwz7vIHq330erA== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,1FE5A37B770AF83D + +042bWtt4q0cB8pRuPUlMVncTP/WAz+mmPw3jXI3LFOBZeK6zFEDpI5M9c2JO+rqp +Za5UkYuIg69V7LngriqRynkRGGQp3xASMLr5NVbKHTE/Ol/iIuxKaCkumZmGXB/z +8bxQF5XN4tbKT4s3sWWmmKMicg6MHvySi3QVRG11PHRu/q7CEFPzJKRQ3fpaNcKD +NTBI5F6GP9ENa/eog4WGENjXS0v4Wa3IfaOhjKXrSxjLUqLH0C8g5WWg5IrXXtuI +pgyJ2kkE3Y/ChU7p7R42we6tBZqF5SiL5kFDn86DmHgCslTiZkIoE5i644sp03Sd +XkHyHu0VIeYp3nDwRA7S98837W4F6i1BnXA5f3EaE3rNGjsxK8zL2pvdCcDYbese +ETfba16HMzLXe1b4RSI3gwhlQ2MNKBwvskkQESf/Ew1DskBY0MCYFxo6hIp6LqMo +HAl5kvCwvuYL2jBdQhkKxU+Leu5Ei8Ie9XYNVy4yUeUAMnSUkVaEs/I8z+Mk8oYq +4QWqOc66XLcI13coDoxmv54kye3RjqdmZI8mg/3LCFotwceDuXyD43/vVhoTPEnp +CqXafV2pw4y95skMHmktI2qvSahaM4P6GGXl8HqmP3b+8V5mxMhNtVnuUha2kouw +DLNFUTg1cCLahM5SRolyA/XTGh7JOkJMYWPeJwN7l3K+lBtHHfj6DHtKEjUcyZFd ++Z55pDoAERumB6+BCnt6X2/0kEDV219RmsgxkGTWdFs+M7Y6EYYRtlinH4nqL6UD +eHWitYIatAHOvdHeNrbXN9L5P3tsUB4HzFa46WWtKqRtbCVTuPVZdw== +-----END RSA PRIVATE KEY----- + +f. end entity certificate and key + (MD2withRSA 1024, subca_cert_sha1_512_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIIB9jCCAaCgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt +vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v +z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6 +c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07 +OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG +9w0BAQIFAANBAIX63Ypi9P71RnC/pcMbhD+wekRFsTzU593X3MC7tyBJtEXwvAZG +iMxXF5A+ohlr7/CrkV7ZTL8PLxnJdY5Y8rQ= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,1FE5A37B770AF83D + +042bWtt4q0cB8pRuPUlMVncTP/WAz+mmPw3jXI3LFOBZeK6zFEDpI5M9c2JO+rqp +Za5UkYuIg69V7LngriqRynkRGGQp3xASMLr5NVbKHTE/Ol/iIuxKaCkumZmGXB/z +8bxQF5XN4tbKT4s3sWWmmKMicg6MHvySi3QVRG11PHRu/q7CEFPzJKRQ3fpaNcKD +NTBI5F6GP9ENa/eog4WGENjXS0v4Wa3IfaOhjKXrSxjLUqLH0C8g5WWg5IrXXtuI +pgyJ2kkE3Y/ChU7p7R42we6tBZqF5SiL5kFDn86DmHgCslTiZkIoE5i644sp03Sd +XkHyHu0VIeYp3nDwRA7S98837W4F6i1BnXA5f3EaE3rNGjsxK8zL2pvdCcDYbese +ETfba16HMzLXe1b4RSI3gwhlQ2MNKBwvskkQESf/Ew1DskBY0MCYFxo6hIp6LqMo +HAl5kvCwvuYL2jBdQhkKxU+Leu5Ei8Ie9XYNVy4yUeUAMnSUkVaEs/I8z+Mk8oYq +4QWqOc66XLcI13coDoxmv54kye3RjqdmZI8mg/3LCFotwceDuXyD43/vVhoTPEnp +CqXafV2pw4y95skMHmktI2qvSahaM4P6GGXl8HqmP3b+8V5mxMhNtVnuUha2kouw +DLNFUTg1cCLahM5SRolyA/XTGh7JOkJMYWPeJwN7l3K+lBtHHfj6DHtKEjUcyZFd ++Z55pDoAERumB6+BCnt6X2/0kEDV219RmsgxkGTWdFs+M7Y6EYYRtlinH4nqL6UD +eHWitYIatAHOvdHeNrbXN9L5P3tsUB4HzFa46WWtKqRtbCVTuPVZdw== +-----END RSA PRIVATE KEY----- + +h. root CRL issuer +-----BEGIN CERTIFICATE----- +MIICKzCCAZSgAwIBAgIBCjANBgkqhkiG9w0BAQQFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDgxNjMwNTdaFw0yOTA0MjUxNjMwNTda +MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQCy6RoQ6nMdeGJ6ijfjqDu3tDmeGLgnvfBcUKvcsvz9Ji3m +oGnTzECo1oLV+A4/TJxOlak+ZiQ5KVyvfMcXLJeT6dRpXQZ+uc6TT3SkBq94VFzX +qkk08z42JNdk1s5uyW8nRfg7+xntajQVrysoPYNDhu21cPnjDkRiBsIdS7+75QID +AQABo3cwdTAdBgNVHQ4EFgQUGcJU6xWo66kI1QBvlfTQKxxmx9IwRwYDVR0jBEAw +PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD +VQQKEwdFeGFtcGxlggEAMAsGA1UdDwQEAwIBAjANBgkqhkiG9w0BAQQFAAOBgQBx +uKL59VInPdCi+8JL4B+S5YjlPL4ZOBHTjS0JlNxtjbGZdfs+3E9PUAdqhMJO4vq7 +XD+hGtgZtwSqGaSUYAtpLdoCr7vvPkcrxYTG2Ak+UiTbZhmJeSswKgFaCmjjdMCy +y64UP2DQfn6Zi0wCfeao0m9s3zRLuJpgaQGiSHTQKA== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,41E4237825CE0148 + +9nbfd7dsaS+fkFYrU1+wTcevjdRLF/j9DUVQh/2bsFlVEYgeL8A+XpvpbXHYBd7H +oBreofDNseibHe4EgISGPK8RymjYutQqPpbHwXd25jlUuUapvvuCj8V6qnhgpqEo +zXL1Nd2c6KZgdySosyWy8JfIBZJ3kwiSkXVwzs8R4bAGrg1VS80GuszvCv8Fzjoc +LuesX6fViE9yFzLsyOvn/W12DKhTXwiXTQYLUupM8zI9Kpozbea52ZIPMJ9HEiaY +JgwNj05w33VxTe/tq3R9vS2Ee6aM4odi6CQEheLsUAnyE0BTsITKzwwTI25WTv25 +W+gwSF3V49a34MojTdlORq5iH0b3rYl7OMdk+99elJSkyQIbVwwOCFrKuSXYXvV7 +s9iMPFUbi+bZ3oP6zM5kVUcH6KyVeYfkuLf2+k1vPlav8/W5v+WfnvUNOBx76Ira +BzVPYmm2V+YFiFL1hugm5Wv+yyx8QcfgXbvhNHoIEj7hh6Ac48FhtqEcBHjuT/gy +7atJJUdOH6hhmD34hkHGnhcDE15ZOczxTLRC9450h5HKsZ0FILRlCBZLmiedycs2 +zqhUpR4jzDG9jKrlDU4ErfMgPLjveZc3/VT3bc+TYfuC8szCaQ5XX1JVcabZ+HQw +pwmA1ONZDVsFzwbJy9+5bgXX+wLD5kaez8EHNDS5PgqgL0UdrWjdRi6e1RwlTDEw +g/d7TZm/iQeL1iUIfkPA1f0ByYIiyd3XQqiQ/Mf1C16lQkhTHDwofFJdL8otT2Ha +dk6fa7lBOnrpbRKUdpJpYfyqHg80BYNPu6BacVXlYqtJtkFK04qHbA== +-----END RSA PRIVATE KEY----- + +i. CRL issued by root CRL issuer +-----BEGIN X509 CRL----- +MIH2MGECAQEwDQYJKoZIhvcNAQEFBQAwHzELMAkGA1UEBhMCVVMxEDAOBgNVBAoT +B0V4YW1wbGUXDTA5MDgwODE2MzU1MFoXDTI4MTAwNzE2MzU1MFqgDjAMMAoGA1Ud +FAQDAgEAMA0GCSqGSIb3DQEBBQUAA4GBAJCd7e25MruuWJP/KmenGC6CR22pQuG+ +XhRaAtpHkNRls8+TfBxm2PtRrXCAcDb68kNLdwvlAlCUwmL6HOx4VB3r+8QRUlDa +T48wVp1ojGU2b2XbPtXiYZBXW6hBsFHGDJM/IAGJPE2PbVYGlBc23A9V9WyPyThi +9XXG1iOTIJ6u +-----END X509 CRL----- + +j. subca CRL issuer +-----BEGIN CERTIFICATE----- +MIICPTCCAaagAwIBAgIBCzANBgkqhkiG9w0BAQQFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDgxNjMwNThaFw0yOTA0MjUxNjMwNTha +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8KICP0bdOZVlR9gZu7TgD +znXgSMER1IQtompgr1mWeZjX4LmRck3/ogHoxwC4RbNPKI3KIihcVdFHw2jgvE0M +mpf2lI50tmhnLitM8P0/q8xUU/KncipADo4hkM5TbpjPeGUBTGLKzGrq7yyT9Uli +Z74rrp1mS59TxcEI2YQMIQIDAQABo3cwdTAdBgNVHQ4EFgQUDGgpD4L8V3aBJPLx +C7diZ0M0wWMwRwYDVR0jBEAwPoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8x +CzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMAsGA1UdDwQEAwIBAjAN +BgkqhkiG9w0BAQQFAAOBgQCcXqRge5UuW0duf/XnUWP4hrm4Q9EHJaiHZDYxI+WW +Ca3OXdsrpgGi+RSgeMtQzlZ7YAwyYVV91U4BnX6s/97Vp5xbR3wr8Qbx67inM8Lp +Tuo+e0nyTxwlwi9cSyy5MfJ8jfzaD+n8akhV+sx0Mmiv77YlrShP24lod55gJHKC +vQ== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,16EC4E2C0855BD5C + +dJHcUsnACMhfESAalWrWrfARnUgGhpp3vupjePUiBJ86YmKaNNr6GAwDukg3EJvs +tboO1QQziLSf9pP7gw82Vp5YctEkk7vJVvCcq3QkZAsjNUHf3m3ne2qg8HngufzY +IS/C3EtKuMr3oqa7P8wvMcsBs1G1ga/YqCWoKzowXhybaYPe20fwUNRtgqgdS5Gy +bAzQB9R+Ua2tCaXb3CBYnrczsYFPhjuULr4qbWgHVBWhnkS3OIz71WqcCoXmvD3s +bsjoZRCJUM6Zavyzs0kVGZogiPdr+KUyzjNNsnxle5cEET6nqkYR16UT/Fvemz9Q +szh/y0gCi1nZb6cw5e9BJyF1GlobzxWyMwwY9L4vZNaBNaVRun+6dRWy0svaPuEy +fV/9Y0/la9scyA5yNHz8xud3Njhj2ghyG5Nqbs3N/pPXRVdh7WNFBnc+L/SIBhhB +/Ha9+OZdqyuMf3G+I1+WVADQr8xQP8/yLEvybZYtssjnuCmQSLPDDQFnp2Z3spax ++AT+T4dRimMjf0mZK/NlRJU9PWqMHzsJGBY1A903oAiiHiRFD10z8vyPBigSDF2W +ct6a8WI1prKho6HbMqeIlSPk+HkdCGZedNNbvRlKl4Y56IsHGAhb3wvQ+94049P9 +wu5thK69jNb7ie3YEefAZTb5kD0h+oB8BILOJ5B29C04JdDe6P6hjGKD7x3nRhHM +nyCUMB/fhYpoXdDhz8CeJ77hFt2zFZRstlDctQsDqLkC0AdvlOFsEFqGM4AkBGcV +f6Y+ykNQB3vEWPZsWqVXHB2vQvk00R55tgu+R5JJ45NLG2TqyOp/4A== +-----END RSA PRIVATE KEY----- + +k. CRL issued by subca CRL issuer +-----BEGIN X509 CRL----- +MIIBLTCBlwIBATANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQMA4GA1UE +ChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMRcNMDkwODA4MTYzNTUxWhcNMjgx +MDA3MTYzNTUxWjAiMCACAQIXDTA5MDgwODE2MzU1MFowDDAKBgNVHRUEAwoBBKAO +MAwwCgYDVR0UBAMCAQAwDQYJKoZIhvcNAQECBQADgYEAbIs7ws4/M24NYrIO0XY6 +UVxni0ZoQa+1R7NwU6unr4jFEVD+W/b+JEMfm0RUmpSa7HrUYsw+NycD3m5CD6VJ +U4iuGGeJvHdrYJiPIYkEiFQnhAGOj8oS/nWtPvDKbuBMZI9atKkypby9At8h9URq +1g/KSIM3rd1PYADdcPsok4I= +-----END X509 CRL----- + diff --git a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/generate.sh b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/generate.sh new file mode 100644 index 00000000000..ff936e5d1f0 --- /dev/null +++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/generate.sh @@ -0,0 +1,255 @@ +# +# Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +#!/bin/ksh +# +# needs ksh to run the script. +set -e + +OPENSSL=openssl + +# generate a self-signed root certificate +if [ ! -f root/finished ]; then + if [ ! -d root ]; then + mkdir root + fi + + # SHA1withRSA 1024 + ${OPENSSL} req -x509 -newkey rsa:1024 -keyout root/root_key_1024.pem \ + -out root/root_cert_sha1_1024.pem -subj "/C=US/O=Example" \ + -config openssl.cnf -reqexts cert_issuer -days 7650 -sha1 \ + -passin pass:passphrase -passout pass:passphrase + + # SHA1withRSA 512 + ${OPENSSL} req -x509 -newkey rsa:512 -keyout root/root_key_512.pem \ + -out root/root_cert_sha1_512.pem -subj "/C=US/O=Example" \ + -config openssl.cnf -reqexts cert_issuer -days 7650 -sha1 \ + -passin pass:passphrase -passout pass:passphrase + + # MD2withRSA 2048 + ${OPENSSL} req -x509 -newkey rsa:2048 -keyout root/root_key_2048.pem \ + -out root/root_cert_md2_2048.pem -subj "/C=US/O=Example" \ + -config openssl.cnf -reqexts cert_issuer -days 7650 -md2 \ + -passin pass:passphrase -passout pass:passphrase + + openssl req -newkey rsa:1024 -keyout root/root_crlissuer_key.pem \ + -out root/root_crlissuer_req.pem -subj "/C=US/O=Example" -days 7650 \ + -passin pass:passphrase -passout pass:passphrase + + openssl x509 -req -in root/root_crlissuer_req.pem -extfile openssl.cnf \ + -extensions crl_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out root/root_crlissuer_cert.pem \ + -CAcreateserial -CAserial root/root_cert.srl -days 7200 \ + -passin pass:passphrase + + touch root/finished +fi + + +# generate subca cert issuer +if [ ! -f subca/finished ]; then + if [ ! -d subca ]; then + mkdir subca + fi + + # RSA 1024 + ${OPENSSL} req -newkey rsa:1024 -keyout subca/subca_key_1024.pem \ + -out subca/subca_req_1024.pem -subj "/C=US/O=Example/OU=Class-1" \ + -days 7650 -passin pass:passphrase -passout pass:passphrase + + # RSA 512 + ${OPENSSL} req -newkey rsa:512 -keyout subca/subca_key_512.pem \ + -out subca/subca_req_512.pem -subj "/C=US/O=Example/OU=Class-1" \ + -days 7650 -passin pass:passphrase -passout pass:passphrase + + # SHA1withRSA 1024 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/subca_req_1024.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out subca/subca_cert_sha1_1024_1024.pem \ + -CAcreateserial -sha1 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 1024 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/subca_req_1024.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_512.pem \ + -CAkey root/root_key_512.pem -out subca/subca_cert_sha1_1024_512.pem \ + -CAcreateserial -sha1 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 512 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/subca_req_512.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out subca/subca_cert_sha1_512_1024.pem \ + -CAcreateserial -sha1 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 512 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/subca_req_512.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_512.pem \ + -CAkey root/root_key_512.pem -out subca/subca_cert_sha1_512_512.pem \ + -CAcreateserial -sha1 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # MD2withRSA 1024 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/subca_req_1024.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out subca/subca_cert_md2_1024_1024.pem \ + -CAcreateserial -md2 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # MD2withRSA 1024 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/subca_req_1024.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_512.pem \ + -CAkey root/root_key_512.pem -out subca/subca_cert_md2_1024_512.pem \ + -CAcreateserial -md2 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + openssl req -newkey rsa:1024 -keyout subca/subca_crlissuer_key.pem \ + -out subca/subca_crlissuer_req.pem -subj "/C=US/O=Example/OU=Class-1" \ + -days 7650 -passin pass:passphrase -passout pass:passphrase + + openssl x509 -req -in subca/subca_crlissuer_req.pem -extfile openssl.cnf \ + -extensions crl_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out subca/subca_crlissuer_cert.pem \ + -CAcreateserial -CAserial root/root_cert.srl -days 7200 \ + -passin pass:passphrase + + touch subca/finished +fi + + +# generate certifiacte for Alice +if [ ! -f subca/alice/finished ]; then + if [ ! -d subca/alice ]; then + mkdir -p subca/alice + fi + + # RSA 1024 + ${OPENSSL} req -newkey rsa:1024 -keyout subca/alice/alice_key_1024.pem \ + -out subca/alice/alice_req_1024.pem \ + -subj "/C=US/O=Example/OU=Class-1/CN=Alice" -days 7650 \ + -passin pass:passphrase -passout pass:passphrase + + # RSA 512 + ${OPENSSL} req -newkey rsa:512 -keyout subca/alice/alice_key_512.pem \ + -out subca/alice/alice_req_512.pem \ + -subj "/C=US/O=Example/OU=Class-1/CN=Alice" -days 7650 \ + -passin pass:passphrase -passout pass:passphrase + + # SHA1withRSA 1024 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/alice/alice_req_1024.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_1024_1024.pem \ + -CAkey subca/subca_key_1024.pem \ + -out subca/alice/alice_cert_sha1_1024_1024.pem -CAcreateserial -sha1 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 1024 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/alice/alice_req_1024.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_512_1024.pem \ + -CAkey subca/subca_key_512.pem \ + -out subca/alice/alice_cert_sha1_1024_512.pem -CAcreateserial -sha1 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 512 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/alice/alice_req_512.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_1024_1024.pem \ + -CAkey subca/subca_key_1024.pem \ + -out subca/alice/alice_cert_sha1_512_1024.pem -CAcreateserial -sha1 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 512 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/alice/alice_req_512.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_512_1024.pem \ + -CAkey subca/subca_key_512.pem \ + -out subca/alice/alice_cert_sha1_512_512.pem -CAcreateserial -sha1 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # MD2withRSA 1024 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/alice/alice_req_1024.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_1024_1024.pem \ + -CAkey subca/subca_key_1024.pem \ + -out subca/alice/alice_cert_md2_1024_1024.pem -CAcreateserial -md2 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # MD2withRSA 1024 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/alice/alice_req_1024.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_512_1024.pem \ + -CAkey subca/subca_key_512.pem \ + -out subca/alice/alice_cert_md2_1024_512.pem -CAcreateserial -md2 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + touch subca/alice/finished +fi + +if [ ! -f root/revoked ]; then + if [ ! -d root ]; then + mkdir root + fi + + if [ ! -f root/index.txt ]; then + touch root/index.txt + echo 00 > root/crlnumber + fi + + openssl ca -gencrl -config openssl.cnf -name ca_top -crldays 7000 -md sha1 \ + -crl_reason superseded -keyfile root/root_crlissuer_key.pem \ + -cert root/root_crlissuer_cert.pem -out root/top_crl.pem \ + -passin pass:passphrase + + touch root/revoked +fi + +if [ ! -f subca/revoked ]; then + if [ ! -d subca ]; then + mkdir subca + fi + + if [ ! -f subca/index.txt ]; then + touch subca/index.txt + echo 00 > subca/crlnumber + fi + + # revoke alice's SHA1withRSA 1024 signed with RSA 1024 + openssl ca -revoke subca/alice/alice_cert_sha1_1024_1024.pem \ + -config openssl.cnf \ + -name ca_subca -crl_reason superseded \ + -keyfile subca/subca_crlissuer_key.pem \ + -cert subca/subca_crlissuer_cert.pem -passin pass:passphrase + + openssl ca -gencrl -config openssl.cnf \ + -name ca_subca -crldays 7000 -md md2 \ + -crl_reason superseded -keyfile subca/subca_crlissuer_key.pem \ + -cert subca/subca_crlissuer_cert.pem \ + -out subca/subca_crl.pem \ + -passin pass:passphrase + + touch subca/revoked +fi diff --git a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/openssl.cnf b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/openssl.cnf new file mode 100644 index 00000000000..5a090f05f3a --- /dev/null +++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/openssl.cnf @@ -0,0 +1,206 @@ +# +# Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# OpenSSL configuration file. +# + +HOME = . +RANDFILE = $ENV::HOME/.rnd + +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = ./top +certs = $dir/certs +crl_dir = $dir/crl +database = $dir/index.txt +unique_subject = no +new_certs_dir = $dir/newcerts +certificate = $dir/cacert.pem +serial = $dir/serial +crlnumber = $dir/crlnumber +crl = $dir/crl.pem +private_key = $dir/private/cakey.pem +RANDFILE = $dir/private/.rand +x509_extensions = v3_ca + +name_opt = ca_default +cert_opt = ca_default + +default_days = 7650 +default_crl_days = 30 +default_md = sha1 +preserve = no + +policy = policy_anything + +[ ca_top ] +dir = ./root +certs = $dir/certs +crl_dir = $dir/crl +database = $dir/index.txt +unique_subject = no +new_certs_dir = $dir/newcerts +certificate = $dir/cacert.pem +serial = $dir/serial +crlnumber = $dir/crlnumber +crl = $dir/crl.pem +private_key = $dir/private/cakey.pem +RANDFILE = $dir/private/.rand + +x509_extensions = v3_ca + +name_opt = ca_default +cert_opt = ca_default + +default_days = 7650 +default_crl_days = 30 +default_md = sha1 +preserve = no + +policy = policy_anything + +[ ca_subca ] +dir = ./subca +certs = $dir/certs +crl_dir = $dir/crl +database = $dir/index.txt +unique_subject = no +new_certs_dir = $dir/newcerts + +certificate = $dir/cacert.pem +serial = $dir/serial +crlnumber = $dir/crlnumber +crl = $dir/crl.pem +private_key = $dir/private/cakey.pem +RANDFILE = $dir/private/.rand + +x509_extensions = usr_cert + +name_opt = ca_default +cert_opt = ca_default + +default_days = 7650 +default_crl_days = 30 +default_md = sha1 +preserve = no + +policy = policy_anything + +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca + +string_mask = nombstr + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = NO +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = A-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 +unstructuredName = An optional company name + + +[ usr_cert ] +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer + +[ v3_req ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = email:example@openjdk.net, RID:1.2.3.4:true + +[ v3_ca ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +basicConstraints = critical,CA:true +keyUsage = keyCertSign + +[ cert_issuer ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +basicConstraints = critical,CA:true +keyUsage = keyCertSign + + +[ crl_issuer ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +keyUsage = cRLSign + + +[ crl_ext ] +authorityKeyIdentifier = keyid:always,issuer:always + +[ ee_of_subca ] +keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyAgreement + +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer diff --git a/jdk/test/sun/security/util/DerValue/BadValue.java b/jdk/test/sun/security/util/DerValue/BadValue.java new file mode 100644 index 00000000000..cbe2c6ab45f --- /dev/null +++ b/jdk/test/sun/security/util/DerValue/BadValue.java @@ -0,0 +1,119 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6864911 + * @summary ASN.1/DER input stream parser needs more work + */ + +import java.io.*; +import sun.security.util.*; +import sun.misc.IOUtils; + +public class BadValue { + + public static void main(String[] args) throws Exception { + + // Test IOUtils.readFully + + // We have 4 bytes + InputStream in = new ByteArrayInputStream(new byte[10]); + byte[] bs = IOUtils.readFully(in, 4, true); + if (bs.length != 4 || in.available() != 6) { + throw new Exception("First read error"); + } + // But only 6 left + bs = IOUtils.readFully(in, 10, false); + if (bs.length != 6 || in.available() != 0) { + throw new Exception("Second read error"); + } + // MAX read as much as it can + in = new ByteArrayInputStream(new byte[10]); + bs = IOUtils.readFully(in, Integer.MAX_VALUE, true); + if (bs.length != 10 || in.available() != 0) { + throw new Exception("Second read error"); + } + // MAX ignore readAll + in = new ByteArrayInputStream(new byte[10]); + bs = IOUtils.readFully(in, Integer.MAX_VALUE, false); + if (bs.length != 10 || in.available() != 0) { + throw new Exception("Second read error"); + } + // 20>10, readAll means failure + in = new ByteArrayInputStream(new byte[10]); + try { + bs = IOUtils.readFully(in, 20, true); + throw new Exception("Third read error"); + } catch (EOFException e) { + // OK + } + int bignum = 10 * 1024 * 1024; + bs = IOUtils.readFully(new SuperSlowStream(bignum), -1, true); + if (bs.length != bignum) { + throw new Exception("Fourth read error"); + } + + // Test DerValue + byte[] input = {0x04, (byte)0x84, 0x40, 0x00, 0x42, 0x46, 0x4b}; + try { + new DerValue(new ByteArrayInputStream(input)); + } catch (IOException ioe) { + // This is OK + } + } +} + +/** + * An InputStream contains a given number of bytes, but only returns one byte + * per read. + */ +class SuperSlowStream extends InputStream { + private int p; + /** + * @param Initial capacity + */ + public SuperSlowStream(int capacity) { + p = capacity; + } + @Override + public int read() throws IOException { + if (p > 0) { + p--; + return 0; + } else { + return -1; + } + } + @Override + public int read(byte b[], int off, int len) throws IOException { + if (len == 0) return 0; + if (p > 0) { + p--; + b[off] = 0; + return 1; + } else { + return -1; + } + } +}