summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2013-11-22 20:57:40 -0500
committerMichael Meeks <michael.meeks@collabora.com>2013-12-02 12:32:02 +0000
commit934941a4cf7c9ee7df69f03e6f0be246499d587f (patch)
treefc37e7a46e181ddee1d42a6fd0aedc8cd1290fc7
parent1ab139fdbe9a7ed3b781730dfecb83a98e0b671b (diff)
Allow worker threads to use their own FastParser instances.
To prevent deadlock during threaded sheet stream parsing. It now deadlocks at a different place. Conflicts: oox/source/core/xmlfilterbase.cxx sc/source/filter/oox/workbookfragment.cxx Change-Id: I0ba0f2c9a257e71b0a340ab14e369b06d5fd8829
-rw-r--r--include/oox/core/xmlfilterbase.hxx8
-rw-r--r--oox/source/core/xmlfilterbase.cxx170
-rw-r--r--sc/source/filter/inc/workbookhelper.hxx6
-rw-r--r--sc/source/filter/oox/workbookfragment.cxx195
-rw-r--r--sc/source/filter/oox/workbookhelper.cxx7
5 files changed, 292 insertions, 94 deletions
diff --git a/include/oox/core/xmlfilterbase.hxx b/include/oox/core/xmlfilterbase.hxx
index 87234fb22328..76eb091b3f2e 100644
--- a/include/oox/core/xmlfilterbase.hxx
+++ b/include/oox/core/xmlfilterbase.hxx
@@ -56,8 +56,7 @@ namespace oox {
namespace core {
class FragmentHandler;
-
-// ============================================================================
+class FastParser;
struct TextField {
com::sun::star::uno::Reference< com::sun::star::text::XText > xText;
@@ -107,7 +106,8 @@ public:
@return True, if the fragment could be imported.
*/
- bool importFragment( const ::rtl::Reference< FragmentHandler >& rxHandler );
+ bool importFragment( const rtl::Reference<FragmentHandler>& rxHandler );
+ bool importFragment( const rtl::Reference<FragmentHandler>& rxHandler, FastParser& rParser );
/** Imports a fragment into an xml::dom::XDocument.
@@ -231,6 +231,8 @@ public:
void importDocumentProperties();
+ FastParser* createParser() const;
+
protected:
virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >
implGetInputStream( utl::MediaDescriptor& rMediaDesc ) const;
diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx
index 98c88863a21b..d1ae6a539c22 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -74,12 +74,6 @@ using utl::MediaDescriptor;
using ::sax_fastparser::FSHelperPtr;
using ::sax_fastparser::FastSerializerHelper;
-
-
-
-
-// ============================================================================
-
namespace {
bool lclHasSuffix( const OUString& rFragmentPath, const OUString& rSuffix )
@@ -88,9 +82,77 @@ bool lclHasSuffix( const OUString& rFragmentPath, const OUString& rSuffix )
return (nSuffixPos >= 0) && rFragmentPath.match( rSuffix, nSuffixPos );
}
-} // namespace
+struct NamespaceIds: public rtl::StaticWithInit<
+ Sequence< beans::Pair< OUString, sal_Int32 > >,
+ NamespaceIds>
+{
+ Sequence< beans::Pair< OUString, sal_Int32 > > operator()()
+ {
+ static const char* const namespaceURIs[] = {
+ "http://www.w3.org/XML/1998/namespace",
+ "http://schemas.openxmlformats.org/package/2006/relationships",
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
+ "http://schemas.openxmlformats.org/drawingml/2006/main",
+ "http://schemas.openxmlformats.org/drawingml/2006/diagram",
+ "http://schemas.openxmlformats.org/drawingml/2006/chart",
+ "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing",
+ "urn:schemas-microsoft-com:vml",
+ "urn:schemas-microsoft-com:office:office",
+ "urn:schemas-microsoft-com:office:word",
+ "urn:schemas-microsoft-com:office:excel",
+ "urn:schemas-microsoft-com:office:powerpoint",
+ "http://schemas.microsoft.com/office/2006/activeX",
+ "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
+ "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
+ "http://schemas.microsoft.com/office/excel/2006/main",
+ "http://schemas.openxmlformats.org/presentationml/2006/main",
+ "http://schemas.openxmlformats.org/markup-compatibility/2006",
+ "http://schemas.openxmlformats.org/spreadsheetml/2006/main/v2",
+ "http://schemas.microsoft.com/office/drawing/2008/diagram",
+ "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
+ };
+
+ static const sal_Int32 namespaceIds[] = {
+ NMSP_xml,
+ NMSP_packageRel,
+ NMSP_officeRel,
+ NMSP_dml,
+ NMSP_dmlDiagram,
+ NMSP_dmlChart,
+ NMSP_dmlChartDr,
+ NMSP_dmlSpreadDr,
+ NMSP_vml,
+ NMSP_vmlOffice,
+ NMSP_vmlWord,
+ NMSP_vmlExcel,
+ NMSP_vmlPowerpoint,
+ NMSP_xls,
+ NMSP_ppt,
+ NMSP_ax,
+ NMSP_xm,
+ NMSP_mce,
+ NMSP_mceTest,
+ NMSP_dsp,
+ NMSP_xlsExtLst
+ };
+
+ Sequence< beans::Pair< OUString, sal_Int32 > > aRet(STATIC_ARRAY_SIZE(namespaceIds));
+ for( sal_Int32 i=0; i<aRet.getLength(); ++i )
+ aRet[i] = make_Pair(
+ OUString::createFromAscii(namespaceURIs[i]),
+ namespaceIds[i]);
+ return aRet;
+ }
+};
-// ============================================================================
+void registerNamespaces( FastParser& rParser )
+{
+ const Sequence< beans::Pair<OUString, sal_Int32> > ids = NamespaceIds::get();
+ for (sal_Int32 i = 0; i < ids.getLength(); ++i)
+ rParser.registerNamespace(ids[i].Second);
+}
+
+} // namespace
struct XmlFilterBaseImpl
{
@@ -105,75 +167,6 @@ struct XmlFilterBaseImpl
explicit XmlFilterBaseImpl( const Reference< XComponentContext >& rxContext ) throw( RuntimeException );
};
-// ----------------------------------------------------------------------------
-
-namespace
-{
- struct NamespaceIds: public rtl::StaticWithInit<
- Sequence< beans::Pair< OUString, sal_Int32 > >,
- NamespaceIds>
- {
- Sequence< beans::Pair< OUString, sal_Int32 > > operator()()
- {
- static const char* const namespaceURIs[] = {
- "http://www.w3.org/XML/1998/namespace",
- "http://schemas.openxmlformats.org/package/2006/relationships",
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
- "http://schemas.openxmlformats.org/drawingml/2006/main",
- "http://schemas.openxmlformats.org/drawingml/2006/diagram",
- "http://schemas.openxmlformats.org/drawingml/2006/chart",
- "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing",
- "urn:schemas-microsoft-com:vml",
- "urn:schemas-microsoft-com:office:office",
- "urn:schemas-microsoft-com:office:word",
- "urn:schemas-microsoft-com:office:excel",
- "urn:schemas-microsoft-com:office:powerpoint",
- "http://schemas.microsoft.com/office/2006/activeX",
- "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
- "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
- "http://schemas.microsoft.com/office/excel/2006/main",
- "http://schemas.openxmlformats.org/presentationml/2006/main",
- "http://schemas.openxmlformats.org/markup-compatibility/2006",
- "http://schemas.openxmlformats.org/spreadsheetml/2006/main/v2",
- "http://schemas.microsoft.com/office/drawing/2008/diagram",
- "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
- };
-
- static const sal_Int32 namespaceIds[] = {
- NMSP_xml,
- NMSP_packageRel,
- NMSP_officeRel,
- NMSP_dml,
- NMSP_dmlDiagram,
- NMSP_dmlChart,
- NMSP_dmlChartDr,
- NMSP_dmlSpreadDr,
- NMSP_vml,
- NMSP_vmlOffice,
- NMSP_vmlWord,
- NMSP_vmlExcel,
- NMSP_vmlPowerpoint,
- NMSP_xls,
- NMSP_ppt,
- NMSP_ax,
- NMSP_xm,
- NMSP_mce,
- NMSP_mceTest,
- NMSP_dsp,
- NMSP_xlsExtLst
- };
-
- Sequence< beans::Pair< OUString, sal_Int32 > > aRet(STATIC_ARRAY_SIZE(namespaceIds));
- for( sal_Int32 i=0; i<aRet.getLength(); ++i )
- aRet[i] = make_Pair(
- OUString::createFromAscii(namespaceURIs[i]),
- namespaceIds[i]);
- return aRet;
- }
- };
-}
-
-// ----------------------------------------------------------------------------
XmlFilterBaseImpl::XmlFilterBaseImpl( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
maFastParser( rxContext ),
@@ -181,10 +174,7 @@ XmlFilterBaseImpl::XmlFilterBaseImpl( const Reference< XComponentContext >& rxCo
maVmlSuffix( ".vml" )
{
// register XML namespaces
- const Sequence< beans::Pair< OUString, sal_Int32 > > ids=
- NamespaceIds::get();
- for( sal_Int32 i=0; i<ids.getLength(); ++i )
- maFastParser.registerNamespace( ids[i].Second );
+ registerNamespaces(maFastParser);
}
XmlFilterBase::XmlFilterBase( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
@@ -220,13 +210,25 @@ void XmlFilterBase::importDocumentProperties()
xImporter->importProperties( xDocumentStorage, xPropSupplier->getDocumentProperties() );
}
+FastParser* XmlFilterBase::createParser() const
+{
+ FastParser* pParser = new FastParser(getComponentContext());
+ registerNamespaces(*pParser);
+ return pParser;
+}
+
OUString XmlFilterBase::getFragmentPathFromFirstType( const OUString& rType )
{
// importRelations() caches the relations map for subsequence calls
return importRelations( OUString() )->getFragmentPathFromFirstType( rType );
}
-bool XmlFilterBase::importFragment( const ::rtl::Reference< FragmentHandler >& rxHandler )
+bool XmlFilterBase::importFragment( const rtl::Reference<FragmentHandler>& rxHandler )
+{
+ return importFragment(rxHandler, mxImpl->maFastParser);
+}
+
+bool XmlFilterBase::importFragment( const rtl::Reference<FragmentHandler>& rxHandler, FastParser& rParser )
{
OSL_ENSURE( rxHandler.is(), "XmlFilterBase::importFragment - missing fragment handler" );
if( !rxHandler.is() )
@@ -280,8 +282,8 @@ bool XmlFilterBase::importFragment( const ::rtl::Reference< FragmentHandler >& r
// own try/catch block for showing parser failure assertion with fragment path
if( xInStrm.is() ) try
{
- mxImpl->maFastParser.setDocumentHandler( xDocHandler );
- mxImpl->maFastParser.parseStream( xInStrm, aFragmentPath );
+ rParser.setDocumentHandler(xDocHandler);
+ rParser.parseStream(xInStrm, aFragmentPath);
return true;
}
catch( Exception& )
diff --git a/sc/source/filter/inc/workbookhelper.hxx b/sc/source/filter/inc/workbookhelper.hxx
index abafb20b7421..1f472c3860f6 100644
--- a/sc/source/filter/inc/workbookhelper.hxx
+++ b/sc/source/filter/inc/workbookhelper.hxx
@@ -53,6 +53,7 @@ namespace oox { namespace core {
class FilterBase;
class FragmentHandler;
class XmlFilterBase;
+ class FastParser;
} }
class ScDocument;
@@ -269,7 +270,10 @@ public:
/** Imports a fragment using the passed fragment handler, which contains
the full path to the fragment stream. */
- bool importOoxFragment( const ::rtl::Reference< ::oox::core::FragmentHandler >& rxHandler );
+ bool importOoxFragment( const rtl::Reference<oox::core::FragmentHandler>& rxHandler );
+
+ bool importOoxFragment( const rtl::Reference<oox::core::FragmentHandler>& rxHandler, oox::core::FastParser& rParser );
+
// BIFF2-BIFF8 specific (MUST NOT be called in OOXML/BIFF12 filter) -------
diff --git a/sc/source/filter/oox/workbookfragment.cxx b/sc/source/filter/oox/workbookfragment.cxx
index 485642c9df45..e9884dacb63e 100644
--- a/sc/source/filter/oox/workbookfragment.cxx
+++ b/sc/source/filter/oox/workbookfragment.cxx
@@ -48,6 +48,8 @@
#include "calcconfig.hxx"
#include <oox/core/fastparser.hxx>
+#include <comphelper/processfactory.hxx>
+#include <officecfg/Office/Calc.hxx>
#include <salhelper/thread.hxx>
#include <osl/conditn.hxx>
@@ -197,6 +199,193 @@ const RecordInfo* WorkbookFragment::getRecordInfos() const
return spRecInfos;
}
+namespace {
+
+class WorkerThread;
+
+typedef std::pair<WorksheetGlobalsRef, FragmentHandlerRef> SheetFragmentHandler;
+typedef std::vector<SheetFragmentHandler> SheetFragmentVector;
+typedef rtl::Reference<WorkerThread> WorkerThreadRef;
+
+struct WorkerThreadData
+{
+ osl::Mutex maMtx;
+ std::vector<WorkerThreadRef> maThreads;
+};
+
+struct IdleWorkerThreadData
+{
+ osl::Mutex maMtx;
+ osl::Condition maCondAdded;
+ std::queue<WorkerThread*> maThreads;
+};
+
+struct
+{
+ boost::scoped_ptr<WorkerThreadData> mpWorkerThreads;
+ boost::scoped_ptr<IdleWorkerThreadData> mpIdleThreads;
+
+} aThreadGlobals;
+
+enum WorkerAction
+{
+ None = 0,
+ TerminateThread,
+ Work
+};
+
+class WorkerThread : public salhelper::Thread
+{
+ WorkbookFragment& mrWorkbookHandler;
+ size_t mnID;
+ FragmentHandlerRef mxHandler;
+ boost::scoped_ptr<oox::core::FastParser> mxParser;
+ osl::Mutex maMtxAction;
+ osl::Condition maCondActionChanged;
+ WorkerAction meAction;
+public:
+ WorkerThread( WorkbookFragment& rWorkbookHandler, size_t nID ) :
+ salhelper::Thread("sheet-import-worker-thread"),
+ mrWorkbookHandler(rWorkbookHandler),
+ mnID(nID),
+ mxParser(rWorkbookHandler.getOoxFilter().createParser()),
+ meAction(None) {}
+
+ virtual void execute()
+ {
+ announceIdle();
+
+ // Keep looping until the terminate request is set.
+ for (maCondActionChanged.wait(); true; maCondActionChanged.wait())
+ {
+ osl::MutexGuard aGuard(maMtxAction);
+ if (!maCondActionChanged.check())
+ // Wait again.
+ continue;
+
+ maCondActionChanged.reset();
+
+ if (meAction == TerminateThread)
+ // End the thread.
+ return;
+
+ if (meAction != Work)
+ continue;
+
+#if 0
+ // TODO : This still deadlocks in the fast parser code.
+ mrWorkbookHandler.importOoxFragment(mxHandler, *mxParser);
+#else
+ double val = rand() / static_cast<double>(RAND_MAX);
+ val *= 1000000; // normalize to 1 second.
+ val *= 1.5; // inflate it a bit.
+ usleep(val); // pretend to be working while asleep.
+#endif
+ announceIdle();
+ }
+ }
+
+ void announceIdle()
+ {
+ // Set itself idle to receive a new task from the main thread.
+ osl::MutexGuard aGuard(aThreadGlobals.mpIdleThreads->maMtx);
+ aThreadGlobals.mpIdleThreads->maThreads.push(this);
+ aThreadGlobals.mpIdleThreads->maCondAdded.set();
+ }
+
+ void terminate()
+ {
+ osl::MutexGuard aGuard(maMtxAction);
+ meAction = TerminateThread;
+ maCondActionChanged.set();
+ }
+
+ void assign( const FragmentHandlerRef& rHandler )
+ {
+ osl::MutexGuard aGuard(maMtxAction);
+ mxHandler = rHandler;
+ meAction = Work;
+ maCondActionChanged.set();
+ }
+};
+
+void importSheetFragments( WorkbookFragment& rWorkbookHandler, SheetFragmentVector& rSheets )
+{
+#if 0 // threaded version
+ size_t nThreadCount = 3;
+ if (nThreadCount > rSheets.size())
+ nThreadCount = rSheets.size();
+
+ // Create new thread globals.
+ aThreadGlobals.mpWorkerThreads.reset(new WorkerThreadData);
+ aThreadGlobals.mpIdleThreads.reset(new IdleWorkerThreadData);
+
+ SheetFragmentVector::iterator it = rSheets.begin(), itEnd = rSheets.end();
+
+ {
+ // Initialize worker threads.
+ osl::MutexGuard aGuard(aThreadGlobals.mpWorkerThreads->maMtx);
+ for (size_t i = 0; i < nThreadCount; ++i)
+ {
+ WorkerThreadRef pThread(new WorkerThread(rWorkbookHandler, i));
+ aThreadGlobals.mpWorkerThreads->maThreads.push_back(pThread);
+ pThread->launch();
+ }
+ }
+
+ for (aThreadGlobals.mpIdleThreads->maCondAdded.wait(); true; aThreadGlobals.mpIdleThreads->maCondAdded.wait())
+ {
+ osl::MutexGuard aGuard(aThreadGlobals.mpIdleThreads->maMtx);
+ if (!aThreadGlobals.mpIdleThreads->maCondAdded.check())
+ // Wait again.
+ continue;
+
+ aThreadGlobals.mpIdleThreads->maCondAdded.reset();
+
+ // Assign work to all idle threads.
+ while (!aThreadGlobals.mpIdleThreads->maThreads.empty())
+ {
+ if (it == itEnd)
+ break;
+
+ WorkerThread* p = aThreadGlobals.mpIdleThreads->maThreads.front();
+ aThreadGlobals.mpIdleThreads->maThreads.pop();
+ p->assign(it->second);
+ ++it;
+ }
+
+ if (it == itEnd)
+ // Finished! Exit the loop.
+ break;
+ }
+
+ {
+ // Terminate all worker threads.
+ osl::MutexGuard aGuard(aThreadGlobals.mpWorkerThreads->maMtx);
+ for (size_t i = 0, n = aThreadGlobals.mpWorkerThreads->maThreads.size(); i < n; ++i)
+ {
+ WorkerThreadRef pWorker = aThreadGlobals.mpWorkerThreads->maThreads[i];
+ pWorker->terminate();
+ if (pWorker.is())
+ pWorker->join();
+ }
+ }
+
+ // Delete all thread globals.
+ aThreadGlobals.mpWorkerThreads.reset();
+ aThreadGlobals.mpIdleThreads.reset();
+
+#else // non-threaded version
+ for( SheetFragmentVector::iterator it = rSheets.begin(), itEnd = rSheets.end(); it != itEnd; ++it)
+ {
+ // import the sheet fragment
+ rWorkbookHandler.importOoxFragment(it->second);
+ }
+#endif
+}
+
+}
+
void WorkbookFragment::finalizeImport()
{
ISegmentProgressBarRef xGlobalSegment = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
@@ -318,11 +507,7 @@ void WorkbookFragment::finalizeImport()
}
// load all worksheets
- for( SheetFragmentVector::iterator aIt = aSheetFragments.begin(), aEnd = aSheetFragments.end(); aIt != aEnd; ++aIt )
- {
- // import the sheet fragment
- importOoxFragment( aIt->second );
- }
+ importSheetFragments(*this, aSheetFragments);
for( std::vector<WorksheetHelper*>::iterator aIt = maHelpers.begin(), aEnd = maHelpers.end(); aIt != aEnd; ++aIt )
{
diff --git a/sc/source/filter/oox/workbookhelper.cxx b/sc/source/filter/oox/workbookhelper.cxx
index 0fca1513c6cf..32c8bd62cc19 100644
--- a/sc/source/filter/oox/workbookhelper.cxx
+++ b/sc/source/filter/oox/workbookhelper.cxx
@@ -1012,11 +1012,16 @@ XmlFilterBase& WorkbookHelper::getOoxFilter() const
return mrBookGlob.getOoxFilter();
}
-bool WorkbookHelper::importOoxFragment( const ::rtl::Reference< FragmentHandler >& rxHandler )
+bool WorkbookHelper::importOoxFragment( const rtl::Reference<FragmentHandler>& rxHandler )
{
return getOoxFilter().importFragment( rxHandler );
}
+bool WorkbookHelper::importOoxFragment( const rtl::Reference<FragmentHandler>& rxHandler, oox::core::FastParser& rParser )
+{
+ return getOoxFilter().importFragment(rxHandler, rParser);
+}
+
// BIFF specific --------------------------------------------------------------
BiffType WorkbookHelper::getBiff() const