changeset 11211:e687603602c1

8201539: Crash in DirectWrite CreateBitmap code when running TestFX test suite Summary: Defer CoUninitialize call to thread exit using dispose hook Reviewed-by: kcr, mennen Contributed-by: pyokagan@gmail.com
author kcr
date Tue, 12 Mar 2019 17:56:10 -0700
parents 14faa538ff7d
children bf9eac8eebef 2c6a0304266d
files modules/javafx.graphics/src/main/java/com/sun/javafx/font/directwrite/DWFactory.java modules/javafx.graphics/src/main/java/com/sun/javafx/font/directwrite/OS.java modules/javafx.graphics/src/main/java/com/sun/prism/GraphicsPipeline.java modules/javafx.graphics/src/main/native-font/directwrite.cpp
diffstat 4 files changed, 79 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/modules/javafx.graphics/src/main/java/com/sun/javafx/font/directwrite/DWFactory.java	Mon Mar 11 16:11:00 2019 +0100
+++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/font/directwrite/DWFactory.java	Tue Mar 12 17:56:10 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 import com.sun.javafx.font.PrismFontFactory;
 import com.sun.javafx.font.PrismFontFile;
 import com.sun.javafx.text.GlyphLayout;
+import com.sun.prism.GraphicsPipeline;
 
 public class DWFactory extends PrismFontFactory {
 
@@ -120,7 +121,24 @@
         checkThread();
         /* Using single threaded WIC Factory as it should only be used by the rendering thread */
         if (WIC_FACTORY == null) {
+            /* Initialize COM in order to create a WICImagingFactory.
+             * It runs on the prism thread and expects no other code in this thread
+             * to interface with COM. */
+            if (!OS.CoInitializeEx(OS.COINIT_APARTMENTTHREADED | OS.COINIT_DISABLE_OLE1DDE)) {
+                return null;
+            }
+
             WIC_FACTORY = OS.WICCreateImagingFactory();
+            if (WIC_FACTORY == null) {
+                return null;
+            }
+
+            GraphicsPipeline.getPipeline().addDisposeHook(() -> {
+                checkThread();
+                WIC_FACTORY.Release();
+                OS.CoUninitialize();
+                WIC_FACTORY = null;
+            });
         }
         return WIC_FACTORY;
     }
--- a/modules/javafx.graphics/src/main/java/com/sun/javafx/font/directwrite/OS.java	Mon Mar 11 16:11:00 2019 +0100
+++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/font/directwrite/OS.java	Tue Mar 12 17:56:10 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,10 @@
     static final int S_OK = 0x0;
     static final int E_NOT_SUFFICIENT_BUFFER = 0x8007007A;
 
+    /* COM init constants */
+    static final int COINIT_APARTMENTTHREADED = 0x2;
+    static final int COINIT_DISABLE_OLE1DDE = 0x4;
+
     /* Direct2D constants */
     static final int D2D1_FACTORY_TYPE_SINGLE_THREADED = 0;
     static final int D2D1_RENDER_TARGET_TYPE_DEFAULT    = 0;
@@ -175,6 +179,9 @@
         return ptr != 0 ? new IWICImagingFactory(ptr) : null;
     }
 
+    static final native boolean CoInitializeEx(int dwCoInit);
+    static final native void CoUninitialize();
+
     private static final native long _NewJFXTextAnalysisSink(char[] text,
                                                              int start,
                                                              int length,
--- a/modules/javafx.graphics/src/main/java/com/sun/prism/GraphicsPipeline.java	Mon Mar 11 16:11:00 2019 +0100
+++ b/modules/javafx.graphics/src/main/java/com/sun/prism/GraphicsPipeline.java	Tue Mar 12 17:56:10 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,9 +31,12 @@
 import com.sun.prism.impl.PrismSettings;
 
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 public abstract class GraphicsPipeline {
 
@@ -56,12 +59,40 @@
         SM3
     }
     private FontFactory fontFactory;
+    private final Set<Runnable> disposeHooks = new HashSet<Runnable>();
 
     public abstract boolean init();
     public void dispose() {
+        notifyDisposeHooks();
         installedPipeline = null;
     }
 
+    /**
+     * Add a dispose hook to be called when the pipeline is disposed.
+     *
+     * @param runnable the {@link Runnable} to be called when the pipeline is disposed
+     */
+    public void addDisposeHook(Runnable runnable) {
+        if (runnable == null) {
+            return;
+        }
+        synchronized (disposeHooks) {
+            disposeHooks.add(runnable);
+        }
+    }
+
+    private void notifyDisposeHooks() {
+        List<Runnable> hooks;
+        synchronized (disposeHooks) {
+            hooks = new ArrayList<Runnable>(disposeHooks);
+            disposeHooks.clear();
+        }
+
+        for (Runnable hook : hooks) {
+            hook.run();
+        }
+    }
+
     public abstract int getAdapterOrdinal(Screen screen);
 
     /*
--- a/modules/javafx.graphics/src/main/native-font/directwrite.cpp	Mon Mar 11 16:11:00 2019 +0100
+++ b/modules/javafx.graphics/src/main/native-font/directwrite.cpp	Tue Mar 12 17:56:10 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -845,30 +845,35 @@
 /*                                                                        */
 /**************************************************************************/
 
+JNIEXPORT jboolean JNICALL OS_NATIVE(CoInitializeEx)
+    (JNIEnv *env, jclass that, jint arg0)
+{
+    HRESULT hr = CoInitializeEx(NULL, (DWORD)arg0);
+
+    /* This means COM has been initialized with a different concurrency model.
+     * This should never happen. */
+    if (hr == RPC_E_CHANGED_MODE) return JNI_FALSE;
+
+    return JNI_TRUE;
+}
+
+JNIEXPORT void JNICALL OS_NATIVE(CoUninitialize)
+    (JNIEnv *env, jclass that)
+{
+    CoUninitialize();
+}
+
 JNIEXPORT jlong JNICALL OS_NATIVE(_1WICCreateImagingFactory)
     (JNIEnv *env, jclass that)
 {
-    /* This routine initialize COM in order to create an WICImagingFactory.
-     * It runs on the prism thread and expects no other codes in this thread
-     * to interface with COM.
-     * Note: This method is called by DWFactory a single time.
-     */
-    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
-
-    /* This means COM has been initialize with a different concurrency model.
-     * This should never happen. */
-    if (hr == RPC_E_CHANGED_MODE) return NULL;
-
     IWICImagingFactory* result = NULL;
-    hr = CoCreateInstance(
+    HRESULT hr = CoCreateInstance(
             CLSID_WICImagingFactory,
             NULL,
             CLSCTX_INPROC_SERVER,
             IID_PPV_ARGS(&result)
             );
 
-    /* Unload COM as no other COM objects will be create directly */
-    CoUninitialize();
     return SUCCEEDED(hr) ? (jlong)result : NULL;
 }