Analysis/Multi-Threading

From Apache OpenOffice Wiki
Jump to: navigation, search

Type: Analysis Status: Final Authors: Kai Sommerfeld, Kay Ramme

More or less frequently people complain about OOo in respect to multi-threading. Either because it is complicated to implement a service, or that there is only few documentation, or that the Uno API is not thread-safe, or that it does not scale etc. Unfortunately it is somehow difficult to name the issues in an orthogonal and complete way. Below you find what we identified to be the (most) pressing ones.

General

  • Issue: OOo does not scale with multiple clients (client threads).
    Expectation: OOo scales with multiple clients e.g. calling on multiple documents.
  • Issue: OOo does not scale on multiple CPUs.
    Expectation: OOo leverages multiple CPUs for executing simultaneous tasks, e.g. printing / loading / saving.
  • Issue: OOo sometimes hangs, waiting for a particular operation to finish.
    Expectation: OOo is always alive and reacts immediately on available commands. At least the “abort” command needs to be available always.
  • Issue: OOo sometimes crashes, when used in ISV scenarios.
    Expectation: OOo can be used by multiple ISV (integration) solutions simultaneously.

Programmability / Uno

  • Issue: There is few to none documentation about the threading model (how can threads be used).
    Expectation: There is a well specified threading model.
  • Issue: There is few to none documentation about the threading architecture (where are threads used to do what and which parts are thread-aware to what extend).
    Expectation: There is a well specified threading architecture, documenting where threads are used and what does that mean for the programmer.
  • Issue: Many OOo Uno API implementations are not thread-safe.
    Expectation: The OOo Uno API implementations can be used by multiple threads and clients simultaneously
    Sample Code: See appendix – Threaded Office Crasher
    Note: Theoretically that means, that the OOo Uno API can not reliable be programmed in languages utilizing dedicated threads for finalization (e.g. CLI, Java), so in practise we do not know of any real problem ever shown up
  • Issue: There is no proof that the OOo Uno API is thread-safe.
    Expectation: There is a specified threading architecture ensuring, that the OOo Uno API is thread-safe.
    Comment: Testing is not sufficiently and realistically possible.
  • Issue: Per definition, every UNO component must be implemented thread-safe.
    Expectation: It can be decided case by case, what the threading architecture of a particular component is.
  • Issue: Per definition, every UNO component must release all locks before calling another object.
    Expectation: A thread-safe component can hold locks, while calling other objects.
    Comment: It is not programmable to release all locks while calling out.
  • Issue: It is hard to implement OLE client components.
    Expectation: OLE client code can be implemented easily as UNO components.
  • Issue: Win32 - OSL threads are always MTA threads.
    Reference: sal/osl/W32/thread.c:103 - CoInitializeEx(COINIT_MULTITHREADED)
    Expectation: OSL threads are threading model neutral (can be used for any kind of COM / OLE programming (STA / MTA)).
  • Issue: There are two competing threading models / architectures in place (Uno, VCL).
    Expectation: There is one well specified threading model / architecture.

VCL (Visual Components Library)

  • Issue: The VCL threading behavior is not platform transparent, it behaves differently on Win32 compared to UNIX.
    Expectation: VCL can be programmed in the same way on any platform.
    Example: On Win32 destroying a window needs to be delegated into the “creator” thread.
  • Issue: Win32 – The VCL API is partly thread-affine.
    Expectation: No OOo API is thread-affine in any kind (depends on threading architecture).
  • Issue: Provides the Solar Mutex, which needs to be locked before every VCL operation.
    Expectation: VCL is thread-transparent (depends on threading architecture).
    Comment: This is error prone and introduces overhead.
  • Issue: VCL releases the Solar Mutex when entering the main loop, even if VCL code is on the stack.
    Expectation: VCL is thread-transparent (depends on threading architecture).
    Comment: This is not viable.
    Sample Code: See appendix – D&D Office Crasher
  • Issue: Win32 – The VCL initializing thread gets initialized as a STA thread.
    Reference: vcl/win/source/app/salinst.cxx:233 - CoInitialize
    Expectation: VCL is threading model neutral.

Office Code

  • Issue: Win32 – Initializing code partly relies on the same thread to enter the main loop (e.g. DDE).
    Expectation: Systems can be initialized by any thread (depends on threading architecture).
  • Issue: Code tricks VCLs thread affinity by posting messages into the main thread.
    Expectation: Code does not workaround threading weaknesses.
    Example: To destroy windows in the “main” thread.
  • Issue: There is thread related dead or unproven code.
    Expectation: thread-aware code is well tested.

Performance

  • Issue: Runtime performance is impacted by many locks becoming con-/de-structed and acquired/released.
    Expectation: Locks are only used in scaling sensitive components.
    Reference: See Appendix / Numbers
  • Issue: Runtime performance is impacted by the need to use interlock counters for reference counting.
    Reference: See Appendix / Numbers
    Expectation: Interlock counters are only used in scaling sensitive components.
  • Issue: Increased code size because of needed thread synchronizations.
    Reference: See Appendix / Numbers
    Expectation: thread-aware code is only used in scaling sensitive parts.

Development Costs

  • Issue: Increased development time because of implementing (not really :-) thread-safe code.
  • Issue: Increased development time because of implementing fine grained synchronization.
  • Issue: Increased maintenance costs due to problems with bugs in thread-safe implementations.
    Expectation: Development most focuses on behavior / performance and less on not usable scalability.

Summary

The current state of OOo threading is unsatisfying in multiple dimensions and areas and urgently needs to be taken care of and cleaned up.

Appendix

Acronyms&Terms

  • VCL: Visual Components Library - OOos GUI abstraction layer.
  • Uno: Universal Network Objects - OOos component model.
  • Win32: MS Windows API.
  • COM: Component Object Model - MS component technology.
  • OLE: MS technology for compound documents and such. OLE is based on COM.
  • OSL: Operating System Layer – Unos platform abstraction for basic operating system tasks, e.g. as file creation, socket communication or process creation.
  • MTA: Multi-Threaded Apartment – An object space which can be populated by multiple threads.
  • STA: Single-Threaded Apartment – An object space which is populated by exactly one thread.
  • Thread: An activity in a process.
  • Lock: A synchronization primitive, such as a pthread MutEx.

Numbers

The following table gives the call numbers for MutExes and interlock counters for a simple scenario. The scenario looks like this:

  • Start the office (soffice.bin).
  • Open an empty Writer document via the menu.
  • Terminate the office via the menu.
Function Calls
osl_acquireMutex 482419
osl_releaseMutex 483692
osl_tryToAcquireMutex 1257
osl_createMutex 7427
osl_destroyMutex 6886
osl_incrementInterlockedCount 1982252
osl_decrementInterlockedCount 1960064

Threaded Office Crasher

The following patch changes the “TextDocuments” example (“<SDK>/examples/DevelopersGuide/Text/TextDocuments.java“, tested with SRC680m124) of the OOo SDK. After applying, two independent threads start to alter the same document. The office typically only survives this some ten seconds, finally dying with varying stacks.

--- examples/DevelopersGuide/Text/TextDocuments.java        2005-01-31 18:03:49.000000000 +0100
+++ TextDocuments.java        2005-11-08 16:26:11.000000000 +0100
@@ -38,6 +38,20 @@ 
  *     
  *************************************************************************/
 
+/******************************************************************* 
+ *** BBBBB   EEEEEE       A     W         W    A     RRRRR   EEEEEE
+ *** B    B  E           A A    W         W   A A    R    R  E
+ *** B    B  E          A   A   W    W    W  A   A   R    R  E
+ *** BBBBB   EEEE       A   A    W  W W  W   A   A   RRRRR   EEEE
+ *** B    B  E          AAAAA    W W   W W   AAAAA   R  R    E
+ *** B    B  E         A     A   W W   W W  A     A  R   R   E
+ *** BBBBB   EEEEEE    A     A    W     W   A     A  R    R  EEEEEE
+ *** 
+ *** - THIS KILLS THE RUNNING OPENOFFICE 
+ *** - THIS MAY MAKE YOU DESKTOP QUITE SLOW TO RESPONSE 
+ *** 
+ *******************************************************************/ 
+ 
 import com.sun.star.awt.Point;
 import com.sun.star.awt.Size;
 import com.sun.star.awt.FontWeight;
@@ -145,7 +159,7 @@ import java.util.Hashtable; 
  *
  * @author  Martin Gallwey, Dietrich Schulten
  */
-public class TextDocuments { 
+public class TextDocuments implements Runnable { 
     // adjust these constant to your local printer!
     private static String sOutputDir;
 
@@ -162,36 +176,45 @@ public class TextDocuments { 
     private XTextContent mxFishSection = null;
     private Random maRandom = null;
     
+        XComponent mxEmptyWriterComponent;
+ 
     /** Creates a new instance of TextDocuments */
     public TextDocuments() {
     }
     
+ 
+        public void run() {
+                while(true) {
+                        try {
+                                runDemo();
+                        }
+                        catch (java.lang.Exception e){
+                        }
+                }
+        }
+ 
     /**
      * @param args the command line arguments
      */
-    public static void main(String[] args) {
-    TextDocuments textDocuments1 = new TextDocuments();
-    try {
-            // output directory for store test;
-            sOutputDir = args[0];
-            
-            textDocuments1.runDemo();
-        }
-        catch (java.lang.Exception e){
-            System.out.println(e.getMessage());
-            e.printStackTrace();
-        }
-        finally {
-            System.exit(0);
-        }
+    public static void main(String[] args) throws Exception {
+                TextDocuments textDocuments1 = new TextDocuments();
+                // create empty swriter document
+                textDocuments1.mxEmptyWriterComponent = textDocuments1.newDocComponent("swriter");
+ 
+                for (int i = 0; i < 2; ++ i) {
+                        System.out.println( "#################### Thread #" + i);
+ 
+                        new Thread(textDocuments1).start();
+                }
     }
     
     protected void runDemo() throws java.lang.Exception {
-            storePrintExample(); // depends on printer name
-            templateExample();   
-            viewCursorExample(); // makes changes to the current document,
-                                 // use with care
-            editingExample();
+//             storePrintExample(); // depends on printer name
+//             templateExample();   
+//             viewCursorExample(); // makes changes to the current document,
+//                                  // use with care
+ 
+                editingExample();
     }
     
     /** Sample for use of templates
@@ -327,11 +350,9 @@ public class TextDocuments { 
      * developer's manual
      */
     private void editingExample () throws java.lang.Exception {
-        // create empty swriter document
-        XComponent xEmptyWriterComponent = newDocComponent("swriter");
         // query its XTextDocument interface to get the text
         mxDoc = (XTextDocument)UnoRuntime.queryInterface(
-            XTextDocument.class, xEmptyWriterComponent);
+            XTextDocument.class, mxEmptyWriterComponent);
         
         // get a reference to the body text of the document
         mxDocText = mxDoc.getText();

Drag&Drop Office Crasher

The following patch changes the “TextDocuments” example (“<SDK>/examples/DevelopersGuide/Text/TextDocuments.java“, tested with SRC680m124) of the OOo SDK.

To test, start the “TextDocuments” example by typing

       make TextDocuments.run

After the Writer window opens, you have ten seconds to type some text (e.g. “dt”<F3>), to select it and to start dragging it. Just keep the drag, the client will try to close the current document and the office dies. This is because of the Solar Mutex getting released by VCL during the yield operation.

*** /so/ws/SRC680/src.m136/odk/examples/DevelopersGuide/Text/TextDocuments.java        2005-01-31 18:03:49.000000000 0100
--- /local/kr/TextDocuments.java        2005-11-22 13:58:59.000000000 +0100
*************** 
*** 38,43 **** 
--- 38,56 ---- 
   *     
   *************************************************************************/
  
+ /******************************************************************* 
+  *** BBBBB   EEEEEE       A     W         W    A     RRRRR   EEEEEE
+  *** B    B  E           A A    W         W   A A    R    R  E
+  *** B    B  E          A   A   W    W    W  A   A   R    R  E
+  *** BBBBB   EEEE       A   A    W  W W  W   A   A   RRRRR   EEEE
+  *** B    B  E          AAAAA    W W   W W   AAAAA   R  R    E
+  *** B    B  E         A     A   W W   W W  A     A  R   R   E
+  *** BBBBB   EEEEEE    A     A    W     W   A     A  R    R  EEEEEE
+  ***
+  *** - THIS KILLS THE RUNNING OPENOFFICE
+  ***
+  *******************************************************************/
+  
  import com.sun.star.awt.Point;
  import com.sun.star.awt.Size;
  import com.sun.star.awt.FontWeight;
*************** public class TextDocuments { 
*** 166,171 **** 
--- 179,194 ---- 
      public TextDocuments() {
      }
      
+     private void openClose_writerDocument() throws Exception {
+         Object desktop = getRemoteServiceManager().createInstanceWithContext("com.sun.star.frame.Desktop", mxRemoteContext);
+         XComponentLoader xComponentLoader   = (XComponentLoader)UnoRuntime.queryInterface(XComponentLoader.class, desktop);
+  
+         XComponent xComponent = xComponentLoader.loadComponentFromURL("private:factory/swriter", "_blank", 0, new PropertyValue[0]);
+  
+                  Thread.sleep(10000);
+                  xComponent.dispose();
+     }
+  
      /**
       * @param args the command line arguments
       */
*************** public class TextDocuments { 
*** 173,181 **** 
      TextDocuments textDocuments1 = new TextDocuments();
      try {
              // output directory for store test;
!             sOutputDir = args[0];
              
!             textDocuments1.runDemo();
          }
          catch (java.lang.Exception e){
              System.out.println(e.getMessage());
--- 196,205 ---- 
      TextDocuments textDocuments1 = new TextDocuments();
      try {
              // output directory for store test;
! //             sOutputDir = args[0];
              
! //             textDocuments1.runDemo();
!                         textDocuments1.openClose_writerDocument();
          }
          catch (java.lang.Exception e){
              System.out.println(e.getMessage());
Personal tools