[prev in list] [next in list] [prev in thread] [next in thread] 

List:       lyx-devel
Subject:    Re: Canceling Background Export
From:       Peter_Kümmel <syntheticpp () gmx ! net>
Date:       2011-11-08 20:44:27
Message-ID: 4EB994AB.4080803 () gmx ! net
[Download RAW message or body]

> Some version of this strategy seems necessary, since one possible reason
> to want to stop the export thread is that one of the converters is in an
> infinite loop. Since we depend on external converters, this kind of
> thing can easily happen and not be under our control. (Of course none of
> the LyX converters would ever behave so badly!)
>
> Here's an idea that might work within the current framework:
>
> 1. Send a signal to the background export thread, which it will
> presumably process no matter what else it might be doing.

Event loop is blocked of the background task. We should change
the implementation of Systemcall to a asynchronous one (no sleep and no processEvents).


> 2. Kill whatever external processes have been started for image
> conversion, etc, and set some kind of boolean so that no more will be
> started while we're at it.

Already done, but we must not kill all available processes. Maybe we
could use the thread pointer to select the correct processes.

> 3. Finally, set another boolean as a signal to the main export routine
> that it should abort. This can be checked when convenient, since my
> sense is that this backend export is not what is expensive.

See the 'extern bool isProcessingEnabled;' hack in attached patch.

It already feels a bit snappier.

Peter

>
> Peter's patch does something along these lines, but at the wrong level,
> it seems to me. We don't want to disable ALL background processing, I
> wouldn't have thought, since that might include image conversions
> demanded by the main thread. And we wouldn't want to kill all background
> processes, for the same reason.
>
> Richard
>


["abort.patch" (text/x-patch)]

Index: src/Converter.cpp
===================================================================
--- src/Converter.cpp	(revision 40157)
+++ src/Converter.cpp	(working copy)
@@ -348,6 +348,12 @@
 	FileName outfile = from_file;
 	for (Graph::EdgePath::const_iterator cit = edgepath.begin();
 	     cit != edgepath.end(); ++cit) {
+
+    extern bool isProcessingEnabled;
+    if (!isProcessingEnabled) {
+      return false;
+    }
+
 		Converter const & conv = converterlist_[*cit];
 		bool dummy = conv.To->dummy() && conv.to != "program";
 		if (!dummy) {
Index: src/frontends/qt4/GuiProgress.cpp
===================================================================
--- src/frontends/qt4/GuiProgress.cpp	(revision 40157)
+++ src/frontends/qt4/GuiProgress.cpp	(working copy)
@@ -184,7 +184,12 @@
 	QMessageBox::information(qApp->focusWidget(), title, message);
 }
 
+void GuiProgress::abortAllProcessesClicked()
+{
+    abortAndDisableProcessing();
+}
 
+
 } // namespace frontend
 } // namespace lyx
 
Index: src/frontends/qt4/GuiProgress.h
===================================================================
--- src/frontends/qt4/GuiProgress.h	(revision 40157)
+++ src/frontends/qt4/GuiProgress.h	(working copy)
@@ -54,7 +54,6 @@
 	void clearMessages();
 	void appendLyXErrMessage(QString const & text);
 
-
 	void clearMessageText();
 	void updateStatusBarMessage(QString const &);
 	void triggerFlush();
@@ -76,6 +75,7 @@
 	void doToggleWarning(QString const & title, QString const & msg, QString const & \
formatted);  void doError(QString const &, QString const &);
 	void doInformation(QString const &, QString const &);
+    void abortAllProcessesClicked();
 
 	void updateWithLyXErr();
 	void startFlushing();
Index: src/frontends/qt4/GuiView.cpp
===================================================================
--- src/frontends/qt4/GuiView.cpp	(revision 40157)
+++ src/frontends/qt4/GuiView.cpp	(working copy)
@@ -249,6 +249,15 @@
 				dynamic_cast<GuiProgress*>(progress_),
 				SIGNAL(clearMessageText()),
 				gv, SLOT(clearMessageText()));
+
+        // fit into LyX
+        QPushButton* abortButton = new QPushButton();
+        abortButton->setText("Abort processes");
+        abortButton->show();
+    
+        // Forward abort signal down to SystemCall via ProgressInterface.
+        connect(abortButton, SIGNAL(clicked()),
+            dynamic_cast<GuiProgress*>(progress_), \
SLOT(abortAllProcessesClicked()));  }
 
 	~GuiViewPrivate()
@@ -554,6 +563,9 @@
 		break;
 	}
 	view->message(msg);
+    if (ProgressInterface::instance()) {
+        ProgressInterface::instance()->enableProcessing();
+    }
 }
 
 
Index: src/output_latex.cpp
===================================================================
--- src/output_latex.cpp	(revision 40157)
+++ src/output_latex.cpp	(working copy)
@@ -685,7 +685,9 @@
 
 	// FIXME UNICODE
 	os << from_utf8(everypar);
-	par.latex(bparams, outerfont, os, runparams, start_pos, end_pos);
+	if (!par.latex(bparams, outerfont, os, runparams, start_pos, end_pos)) {
+    return;
+  }
 
 	// Make sure that \\par is done with the font of the last
 	// character if this has another size as the default.
Index: src/Paragraph.cpp
===================================================================
--- src/Paragraph.cpp	(revision 40157)
+++ src/Paragraph.cpp	(working copy)
@@ -2278,7 +2278,7 @@
 
 
 // This one spits out the text of the paragraph
-void Paragraph::latex(BufferParams const & bparams,
+bool Paragraph::latex(BufferParams const & bparams,
 	Font const & outerfont,
 	otexstream & os,
 	OutputParams const & runparams,
@@ -2292,7 +2292,7 @@
 		bparams.documentClass().plainLayout() : *d->layout_;
 
 	if (!force && style.inpreamble)
-		return;
+		return true;;
 
 	bool const allowcust = allowParagraphCustomization();
 
@@ -2339,7 +2339,14 @@
 			column += d->startTeXParParams(bparams, os, runparams);
 	}
 
+
 	for (pos_type i = 0; i < size(); ++i) {
+
+    extern bool isProcessingEnabled;
+    if (!isProcessingEnabled) {
+      return false;
+    }
+
 		// First char in paragraph or after label?
 		if (i == body_pos) {
 			if (body_pos > 0) {
@@ -2525,6 +2532,8 @@
 		// Set the encoding to that returned from latexSpecialChar (see
 		// comment for encoding member in OutputParams.h)
 		runparams.encoding = rp.encoding;
+
+    return true;
 	}
 
 	// If we have an open font definition, we have to close it
@@ -2563,6 +2572,8 @@
 	}
 
 	LYXERR(Debug::LATEX, "Paragraph::latex... done " << this);
+
+  return true;
 }
 
 
Index: src/Paragraph.h
===================================================================
--- src/Paragraph.h	(revision 40157)
+++ src/Paragraph.h	(working copy)
@@ -191,7 +191,7 @@
 	void validate(LaTeXFeatures &) const;
 
 	/// \param force means: output even if layout.inpreamble is true.
-	void latex(BufferParams const &, Font const & outerfont, otexstream &,
+	bool latex(BufferParams const &, Font const & outerfont, otexstream &,
 		   OutputParams const &, int start_pos = 0, int end_pos = -1,
 		   bool force = false) const;
 
Index: src/support/ProgressInterface.h
===================================================================
--- src/support/ProgressInterface.h	(revision 40157)
+++ src/support/ProgressInterface.h	(working copy)
@@ -30,6 +30,7 @@
 	virtual void appendError(QString const &) = 0;
 	virtual void clearMessages() = 0;
 	virtual void lyxerrFlush() = 0;
+    void abortAndDisbaleProcessing();
 
 	/// Alert interface
 	virtual void warning(QString const & title, QString const & message) = 0;
@@ -43,6 +44,10 @@
 	static void setInstance(ProgressInterface*);
 	static ProgressInterface* instance();
 
+    // calls from Gui into SystemCall
+    void abortAndDisableProcessing();
+    void enableProcessing();
+
 protected:
 	ProgressInterface() {}
 };
Index: src/support/Systemcall.cpp
===================================================================
--- src/support/Systemcall.cpp	(revision 40157)
+++ src/support/Systemcall.cpp	(working copy)
@@ -32,7 +32,10 @@
 #include <QThread>
 #include <QCoreApplication>
 #include <QDebug>
+#include <QMutexLocker>
 
+
+
 #define USE_QPROCESS
 
 
@@ -45,6 +48,7 @@
 };
 
 
+bool isProcessingEnabled = true;
 
 
 using namespace std;
@@ -93,8 +97,20 @@
 }
 
 
+void ProgressInterface::abortAndDisableProcessing()
+{
+    SystemcallPrivate::setProcessingEnabled(false);
+    SystemcallPrivate::killCurrentProcesses();
+}
 
 
+void ProgressInterface::enableProcessing()
+{
+  SystemcallPrivate::setProcessingEnabled(true);
+}
+
+
+
 // Reuse of instance
 #ifndef USE_QPROCESS
 int Systemcall::startscript(Starttype how, string const & what,
@@ -236,6 +252,11 @@
 {
 	lyxerr << "\nRunning: " << what << endl;
 
+    if (!SystemcallPrivate::isProcessingEnabled()) {
+        LYXERR0("Systemcall: disabled ");
+        return 30;
+    }
+
 	string outfile;
 	string errfile;
 	QString cmd = QString::fromLocal8Bit(
@@ -257,6 +278,8 @@
 		return 0;
 	}
 
+    // when we are here we know that we don't use SystemCall asynchronously
+    d.appendAsKillableProcess();
 	if (!d.waitWhile(SystemcallPrivate::Running, process_events,
 			 os::timeout_min() * 60 * 1000)) {
 		LYXERR0("Systemcall: '" << cmd << "' did not finish!");
@@ -337,6 +360,9 @@
 	connect(process_, SIGNAL(finished(int, QProcess::ExitStatus)), \
SLOT(processFinished(int, QProcess::ExitStatus)));  }
 
+bool SystemcallPrivate::is_processing_enabled_ = true;
+QMutex SystemcallPrivate::killable_processes_mutex_;
+QSet<QProcess*> SystemcallPrivate::killable_processes_;
 
 void SystemcallPrivate::startProcess(QString const & cmd, string const & path)
 {
@@ -553,6 +579,7 @@
 void SystemcallPrivate::killProcess()
 {
 	killProcess(process_);
+    removeAsKillableProcess();
 }
 
 
@@ -567,8 +594,55 @@
 	}
 }
 
+void SystemcallPrivate::enableProcessing()
+{
+  SystemcallPrivate::setProcessingEnabled(true);
+}
 
+void SystemcallPrivate::abortAndStopFurtherProcessing()
+{
+  SystemcallPrivate::setProcessingEnabled(false);
+  process_->kill();
+}
 
+bool SystemcallPrivate::isProcessingEnabled()
+{
+   return is_processing_enabled_;
+}
+
+
+
+void SystemcallPrivate::setProcessingEnabled(bool enable)
+{
+  is_processing_enabled_ = enable;
+  ::isProcessingEnabled = enable;
+}
+
+
+void SystemcallPrivate::appendAsKillableProcess()
+{
+    QMutexLocker lock(&killable_processes_mutex_);
+    killable_processes_.insert(process_);
+}
+
+void SystemcallPrivate::removeAsKillableProcess()
+{
+    QMutexLocker lock(&killable_processes_mutex_);
+    killable_processes_.remove(process_);
+}
+
+void SystemcallPrivate::killCurrentProcesses()
+{
+    QMutexLocker lock(&killable_processes_mutex_);
+    Q_FOREACH(QProcess* p, killable_processes_) {
+        p->kill();
+    }
+    killable_processes_.clear();
+}
+
+
+
+
 #include "moc_SystemcallPrivate.cpp"
 #endif
 
Index: src/support/SystemcallPrivate.h
===================================================================
--- src/support/SystemcallPrivate.h	(revision 40157)
+++ src/support/SystemcallPrivate.h	(working copy)
@@ -14,6 +14,7 @@
 
 #include <QObject>
 #include <QProcess>
+#include <QMutex>
 
 #include <string>
 
@@ -55,6 +56,13 @@
 	
 	static void killProcess(QProcess * p);
 
+    static bool isProcessingEnabled();
+    static void setProcessingEnabled(bool);
+    
+    void appendAsKillableProcess();
+    void removeAsKillableProcess();
+    
+    static void killCurrentProcesses();
 
 public Q_SLOTS:
 	void stdOut();
@@ -62,8 +70,11 @@
 	void processError(QProcess::ProcessError);
 	void processStarted();
 	void processFinished(int, QProcess::ExitStatus status);
+  
+    void abortAndStopFurtherProcessing();
+    void enableProcessing();
+  
 
-
 private:
 	/// Pointer to the process to monitor.
 	QProcess * process_;
@@ -91,6 +102,10 @@
 	void processEvents();
 	void killProcess();	
 
+    static bool is_processing_enabled_;
+    
+    static QMutex killable_processes_mutex_;
+    static QSet<QProcess*> killable_processes_;
 };
 
 } // namespace support



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic