John,

attached is some rough and ready, proof of principle code that 
appears to do the job.

To generate an autosave type
        buffer-auto-save
in the minibuffer. You should get "Autosaving Buffer" printed to the 
console. If you have the Child Processes dialog open, you should also
get something flashing up there, indicating that the process is being
stored by the ForkedController as we desire.

I certainly can't generate zombies, but maybe you'll have a go too?

Good night!
Angus
? src/support/patch
Index: src/frontends/controllers/ControlForks.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/controllers/ControlForks.C,v
retrieving revision 1.9
diff -u -p -r1.9 ControlForks.C
--- src/frontends/controllers/ControlForks.C	5 Sep 2002 15:14:21 -0000	1.9
+++ src/frontends/controllers/ControlForks.C	24 Oct 2002 20:36:19 -0000
@@ -42,8 +42,9 @@ vector<pid_t> const ControlForks::getPID
 
 string const ControlForks::getCommand(pid_t pid) const
 {
-	ForkedcallsController const & fcc = ForkedcallsController::get();
-	return fcc.getCommand(pid);
+//  	ForkedcallsController const & fcc = ForkedcallsController::get();
+//  	return fcc.getCommand(pid);
+	return string();
 }
 
 
Index: src/lyx_cb.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/lyx_cb.C,v
retrieving revision 1.185
diff -u -p -r1.185 lyx_cb.C
--- src/lyx_cb.C	15 Aug 2002 14:33:11 -0000	1.185
+++ src/lyx_cb.C	24 Oct 2002 20:36:20 -0000
@@ -243,28 +243,43 @@ void QuitLyX()
 }
 
 
+#include "support/forkedcontr.h"
+#include "support/forkedcall.h"
 
-void AutoSave(BufferView * bv)
-	// should probably be moved into BufferList (Lgb)
-	// Perfect target for a thread...
-{
-	if (!bv->available())
-		return;
+class AutoSaveBuffer : public ForkedBase {
+public:
+	AutoSaveBuffer(BufferView & bv, string const & fname)
+		: bv_(bv), fname_(fname) {}
+	int start();
+
+private:
+	int save();
+	BufferView & bv_;
+	string fname_;
+};
 
-	if (bv->buffer()->isBakClean() || bv->buffer()->isReadonly()) {
-		// We don't save now, but we'll try again later
-		bv->owner()->resetAutosaveTimer();
-		return;
+
+int AutoSaveBuffer::start()
+{
+	retval_ = 0;
+	pid_ = save();
+	if (pid_ <= 0) { // child or fork failed.
+		retval_ = 1;
+		return retval_;
 	}
 
-	bv->owner()->message(_("Autosaving current document..."));
+	// Non-blocking execution.
+	// Integrate into the Controller
+	ForkedcallsController & contr = ForkedcallsController::get();
+	contr.addCall(*this);
+
+	return retval_;	
+}
 
-	// create autosave filename
-	string fname =	bv->buffer()->filePath();
-	fname += "#";
-	fname += OnlyFilename(bv->buffer()->fileName());
-	fname += "#";
 
+int AutoSaveBuffer::save()
+{
+			
 	// tmp_ret will be located (usually) in /tmp
 	// will that be a problem?
 	pid_t const pid = fork(); // If you want to debug the autosave
@@ -278,9 +293,9 @@ void AutoSave(BufferView * bv)
 
 		string const tmp_ret = lyx::tempName(string(), "lyxauto");
 		if (!tmp_ret.empty()) {
-			bv->buffer()->writeFile(tmp_ret);
+			bv_.buffer()->writeFile(tmp_ret);
 			// assume successful write of tmp_ret
-			if (!lyx::rename(tmp_ret, fname)) {
+			if (!lyx::rename(tmp_ret, fname_)) {
 				failed = true;
 				// most likely couldn't move between filesystems
 				// unless write of tmp_ret failed
@@ -293,18 +308,45 @@ void AutoSave(BufferView * bv)
 
 		if (failed) {
 			// failed to write/rename tmp_ret so try writing direct
-			if (!bv->buffer()->writeFile(fname)) {
+			if (!bv_.buffer()->writeFile(fname_)) {
 				// It is dangerous to do this in the child,
 				// but safe in the parent, so...
 				if (pid == -1)
-					bv->owner()->message(_("Autosave failed!"));
+					bv_.owner()->message(_("Autosave failed!"));
 			}
 		}
 		if (pid == 0) { // we are the child so...
 			_exit(0);
 		}
 	}
+	return pid;
+}
+ 
+
+void AutoSave(BufferView * bv)
+	// should probably be moved into BufferList (Lgb)
+	// Perfect target for a thread...
+{
+	if (!bv->available())
+		return;
+
+	if (bv->buffer()->isBakClean() || bv->buffer()->isReadonly()) {
+		// We don't save now, but we'll try again later
+		bv->owner()->resetAutosaveTimer();
+		return;
+	}
+
+	bv->owner()->message(_("Autosaving current document..."));
+
+	// create autosave filename
+	string fname = bv->buffer()->filePath();
+	fname += "#";
+	fname += OnlyFilename(bv->buffer()->fileName());
+	fname += "#";
 
+	AutoSaveBuffer autosave(*bv, fname);
+	autosave.start();
+	
 	bv->buffer()->markBakClean();
 	bv->owner()->resetAutosaveTimer();
 }
Index: src/graphics/GraphicsConverter.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/graphics/GraphicsConverter.C,v
retrieving revision 1.21
diff -u -p -r1.21 GraphicsConverter.C
--- src/graphics/GraphicsConverter.C	10 Sep 2002 16:04:10 -0000	1.21
+++ src/graphics/GraphicsConverter.C	24 Oct 2002 20:36:20 -0000
@@ -48,7 +48,7 @@ struct Converter::Impl : public boost::s
 	 *  Cleans-up the temporary files, emits the finishedConversion
 	 *  signal and removes the Converter from the list of all processes.
 	 */
-	void converted(string const & cmd, pid_t pid, int retval);
+	void converted(pid_t pid, int retval);
 
 	/** At the end of the conversion process inform the outside world
 	 *  by emitting a signal.
@@ -191,7 +191,7 @@ Converter::Impl::Impl(string const & fro
 void Converter::Impl::startConversion()
 {
 	if (!valid_process_) {
-		converted(string(), 0, 1);
+		converted(0, 1);
 		return;
 	}
 
@@ -200,19 +200,18 @@ void Converter::Impl::startConversion()
 	convert_ptr.reset(new Forkedcall::SignalType);
 
 	convert_ptr->connect(
-		boost::bind(&Impl::converted, this, _1, _2, _3));
+		boost::bind(&Impl::converted, this, _1, _2));
 
 	Forkedcall call;
 	int retval = call.startscript(script_command_, convert_ptr);
 	if (retval > 0) {
 		// Unable to even start the script, so clean-up the mess!
-		converted(string(), 0, 1);
+		converted(0, 1);
 	}
 }
 
 
-void Converter::Impl::converted(string const & /* cmd */,
-				pid_t /* pid */, int retval)
+void Converter::Impl::converted(pid_t /* pid */, int retval)
 {
 	if (finished_)
 		// We're done already!
Index: src/graphics/PreviewLoader.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/graphics/PreviewLoader.C,v
retrieving revision 1.33
diff -u -p -r1.33 PreviewLoader.C
--- src/graphics/PreviewLoader.C	17 Oct 2002 15:56:42 -0000	1.33
+++ src/graphics/PreviewLoader.C	24 Oct 2002 20:36:20 -0000
@@ -102,12 +102,14 @@ struct InProgress {
 	///
 	pid_t pid;
 	///
+	string command;
+	///
 	string metrics_file;
 	///
 	BitmapFile snippets;
 };
 
-typedef map<string, InProgress>  InProgressProcesses;
+typedef map<pid_t, InProgress>  InProgressProcesses;
 
 typedef InProgressProcesses::value_type InProgressProcess;
 
@@ -139,7 +141,7 @@ struct PreviewLoader::Impl : public boos
 
 private:
 	/// Called by the Forkedcall process that generated the bitmap files.
-	void finishedGenerating(string const &, pid_t, int);
+	void finishedGenerating(pid_t, int);
 	///
 	void dumpPreamble(ostream &) const;
 	///
@@ -481,7 +483,7 @@ void PreviewLoader::Impl::startLoading()
 	// Initiate the conversion from LaTeX to bitmap images files.
 	Forkedcall::SignalTypePtr convert_ptr(new Forkedcall::SignalType);
 	convert_ptr->connect(
-		boost::bind(&Impl::finishedGenerating, this, _1, _2, _3));
+		boost::bind(&Impl::finishedGenerating, this, _1, _2));
 
 	Forkedcall call;
 	int ret = call.startscript(command, convert_ptr);
@@ -495,28 +497,28 @@ void PreviewLoader::Impl::startLoading()
 
 	// Store the generation process in a list of all such processes
 	inprogress.pid = call.pid();
-	in_progress_[command] = inprogress;
+	inprogress.command = command;
+	in_progress_[inprogress.pid] = inprogress;
 }
 
 
-void PreviewLoader::Impl::finishedGenerating(string const & command,
-					     pid_t /* pid */, int retval)
+void PreviewLoader::Impl::finishedGenerating(pid_t pid, int retval)
 {
+	// Paranoia check!
+	InProgressProcesses::iterator git = in_progress_.find(pid);
+	if (git == in_progress_.end()) {
+		lyxerr << "PreviewLoader::finishedGenerating(): unable to find "
+			"data for PID " << pid << endl;
+		return;
+	}
+
+	string const command = git->second.command;
 	string const status = retval > 0 ? "failed" : "succeeded";
 	lyxerr[Debug::GRAPHICS] << "PreviewLoader::finishedInProgress("
 				<< retval << "): processing " << status
 				<< " for " << command << endl;
 	if (retval > 0)
 		return;
-
-	// Paranoia check!
-	InProgressProcesses::iterator git = in_progress_.find(command);
-	if (git == in_progress_.end()) {
-		lyxerr << "PreviewLoader::finishedGenerating(): unable to find "
-			"data for\n"
-		       << command << "!" << endl;
-		return;
-	}
 
 	// Read the metrics file, if it exists
 	vector<double> ascent_fractions(git->second.snippets.size());
Index: src/support/forkedcall.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcall.C,v
retrieving revision 1.7
diff -u -p -r1.7 forkedcall.C
--- src/support/forkedcall.C	25 Sep 2002 10:03:41 -0000	1.7
+++ src/support/forkedcall.C	24 Oct 2002 20:36:20 -0000
@@ -53,62 +53,11 @@ using std::strerror;
 #endif
 
 
-Forkedcall::Forkedcall()
+ForkedBase::ForkedBase()
 	: pid_(0), retval_(0)
 {}
 
 
-int Forkedcall::startscript(Starttype wait, string const & what)
-{
-	if (wait == Wait) {
-		command_ = what;
-		retval_  = 0;
-
-		pid_ = generateChild();
-		if (pid_ <= 0) { // child or fork failed.
-			retval_ = 1;
-		} else {
-			retval_ = waitForChild();
-		}
-
-		return retval_;
-	}
-
-	// DontWait
-	retval_ = startscript(what, SignalTypePtr());
-	return retval_;
-}
-
-
-int Forkedcall::startscript(string const & what, SignalTypePtr signal)
-{
-	command_ = what;
-	signal_  = signal;
-	retval_  = 0;
-
-	pid_ = generateChild();
-	if (pid_ <= 0) { // child or fork failed.
-		retval_ = 1;
-		return retval_;
-	}
-
-	// Non-blocking execution.
-	// Integrate into the Controller
-	ForkedcallsController & contr = ForkedcallsController::get();
-	contr.addCall(*this);
-
-	return retval_;
-}
-
-
-void Forkedcall::emitSignal()
-{
-	if (signal_.get()) {
-		signal_->operator()(command_, pid_, retval_);
-	}
-}
-
-
 namespace {
 
 class Murder : public boost::signals::trackable {
@@ -157,9 +106,17 @@ private:
 } // namespace anon
 
 
-void Forkedcall::kill(int tol)
+void ForkedBase::emitSignal()
 {
-	lyxerr << "Forkedcall::kill(" << tol << ")" << std::endl;
+	if (signal_.get()) {
+		signal_->operator()(pid_, retval_);
+	}
+}
+
+
+void ForkedBase::kill(int tol)
+{
+	lyxerr << "ForkedBase::kill(" << tol << ")" << std::endl;
 	if (pid() == 0) {
 		lyxerr << "Can't kill non-existent process!" << endl;
 		return;
@@ -184,7 +141,7 @@ void Forkedcall::kill(int tol)
 
 
 // Wait for child process to finish. Returns returncode from child.
-int Forkedcall::waitForChild() {
+int ForkedBase::waitForChild() {
 	// We'll pretend that the child returns 1 on all error conditions.
 	retval_ = 1;
 	int status;
@@ -215,6 +172,49 @@ int Forkedcall::waitForChild() {
 			wait = false;
 		}
 	}
+	return retval_;
+}
+
+
+int Forkedcall::startscript(Starttype wait, string const & what)
+{
+	if (wait == Wait) {
+		command_ = what;
+		retval_  = 0;
+
+		pid_ = generateChild();
+		if (pid_ <= 0) { // child or fork failed.
+			retval_ = 1;
+		} else {
+			retval_ = waitForChild();
+		}
+
+		return retval_;
+	}
+
+	// DontWait
+	retval_ = startscript(what, SignalTypePtr());
+	return retval_;
+}
+
+
+int Forkedcall::startscript(string const & what, SignalTypePtr signal)
+{
+	command_ = what;
+	signal_  = signal;
+	retval_  = 0;
+
+	pid_ = generateChild();
+	if (pid_ <= 0) { // child or fork failed.
+		retval_ = 1;
+		return retval_;
+	}
+
+	// Non-blocking execution.
+	// Integrate into the Controller
+	ForkedcallsController & contr = ForkedcallsController::get();
+	contr.addCall(*this);
+
 	return retval_;
 }
 
Index: src/support/forkedcall.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcall.h,v
retrieving revision 1.6
diff -u -p -r1.6 forkedcall.h
--- src/support/forkedcall.h	25 Sep 2002 10:03:41 -0000	1.6
+++ src/support/forkedcall.h	24 Oct 2002 20:36:20 -0000
@@ -33,11 +33,11 @@
 #include "LString.h"
 
 #include <boost/shared_ptr.hpp>
-#include <boost/signals/signal3.hpp>
+#include <boost/signals/signal2.hpp>
 
 #include <sys/types.h>
 
-class Forkedcall {
+class ForkedBase {
 public:
 	///
 	enum Starttype {
@@ -48,25 +48,12 @@ public:
 	};
 
 	///
-	Forkedcall();
-
-	/** Start the child process.
-	 *
-	 *  The command "what" is passed to fork() for execution.
-	 *
-	 *  There are two startscript commands available. They differ in that
-	 *  the second receives a signal that is executed on completion of
-	 *  the command. This makes sense only for a command executed
-	 *  in the background, ie DontWait.
-	 *
-	 *  The other startscript command can be executed either blocking
-	 *  or non-blocking, but no signal will be emitted on finishing.
-	 */
-	int startscript(Starttype, string const & what);
+	ForkedBase();
+	///
+	virtual ~ForkedBase() {}
 
 	/** A SignalType signal is can be emitted once the forked process
 	 *  has finished. It passes:
-	 *  the commandline string;
 	 *  the PID of the child and;
 	 *  the return value from the child.
 	 *
@@ -74,7 +61,7 @@ public:
 	 *  we can return easily to C++ methods, rather than just globally
 	 *  accessible functions.
 	 */
-	typedef boost::signal3<void, string const &, pid_t, int> SignalType;
+	typedef boost::signal2<void, pid_t, int> SignalType;
 
 	/** The signal is connected in the calling routine to the desired
 	 *  slot. We pass a shared_ptr rather than a reference to the signal
@@ -86,9 +73,6 @@ public:
 	 */
 	typedef boost::shared_ptr<SignalType> SignalTypePtr;
 
-	///
-	int startscript(string const & what, SignalTypePtr);
-
 	/** Invoking the following methods makes sense only if the command
 	 *  is running asynchronously!
 	 */
@@ -115,27 +99,51 @@ public:
 	 *  When the child is dead, the callback is called.
 	 */
 	void kill(int tolerance = 5);
-	///
-	string const & command() const { return command_; }
 
-private:
+protected:
+
+	/// Wait for child process to finish. Updates returncode from child.
+	int waitForChild();
+
 	/// Callback function
 	SignalTypePtr signal_;
 
-	/// Commmand line
-	string command_;
-
 	/// Process ID of child
 	pid_t pid_;
 
 	/// Return value from child
 	int retval_;
+};
+
+
+class Forkedcall : public ForkedBase {
+public:
+	/** Start the child process.
+	 *
+	 *  The command "what" is passed to fork() for execution.
+	 *
+	 *  There are two startscript commands available. They differ in that
+	 *  the second receives a signal that is executed on completion of
+	 *  the command. This makes sense only for a command executed
+	 *  in the background, ie DontWait.
+	 *
+	 *  The other startscript command can be executed either blocking
+	 *  or non-blocking, but no signal will be emitted on finishing.
+	 */
+	int startscript(Starttype, string const & what);
 
 	///
-	pid_t generateChild();
+	int startscript(string const & what, SignalTypePtr);
 
-	/// Wait for child process to finish. Updates returncode from child.
-	int waitForChild();
+	///
+	string const & command() const { return command_; }
+
+private:
+	/// Commmand line
+	string command_;
+
+	///
+	pid_t generateChild();
 };
 
 #endif // FORKEDCALL_H
Index: src/support/forkedcontr.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcontr.C,v
retrieving revision 1.5
diff -u -p -r1.5 forkedcontr.C
--- src/support/forkedcontr.C	25 Sep 2002 10:03:41 -0000	1.5
+++ src/support/forkedcontr.C	24 Oct 2002 20:36:20 -0000
@@ -71,13 +71,14 @@ ForkedcallsController::~ForkedcallsContr
 }
 
 
-// Add child process information to the list of controlled processes
-void ForkedcallsController::addCall(Forkedcall const &newcall)
+void ForkedcallsController::startTimeout()
 {
 	if (!timeout_->running())
 		timeout_->start();
+}
 
-	Forkedcall * call = new Forkedcall(newcall);
+void ForkedcallsController::push_back(ForkedBase * call)
+{
 	forkedCalls.push_back(call);
 	childrenChanged();
 }
@@ -91,7 +92,7 @@ void ForkedcallsController::timer()
 
 	for (ListType::iterator it = forkedCalls.begin();
 	     it != forkedCalls.end(); ++it) {
-		Forkedcall * actCall = *it;
+		ForkedBase * actCall = *it;
 
 		pid_t pid = actCall->pid();
 		int stat_loc;
@@ -179,17 +180,17 @@ vector<pid_t> const ForkedcallsControlle
 
 
 // Get the command string of the process.
-string const ForkedcallsController::getCommand(pid_t pid) const
-{
-	ListType::const_iterator it =
-		find_if(forkedCalls.begin(), forkedCalls.end(),
-			lyx::compare_memfun(&Forkedcall::pid, pid));
+//  string const ForkedcallsController::getCommand(pid_t pid) const
+//  {
+//  	ListType::const_iterator it =
+//  		find_if(forkedCalls.begin(), forkedCalls.end(),
+//  			lyx::compare_memfun(&Forkedcall::pid, pid));
 
-	if (it == forkedCalls.end())
-		return string();
+//  	if (it == forkedCalls.end())
+//  		return string();
 
-	return (*it)->command();
-}
+//  	return (*it)->command();
+//  }
 
 
 // Kill the process prematurely and remove it from the list
Index: src/support/forkedcontr.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcontr.h,v
retrieving revision 1.7
diff -u -p -r1.7 forkedcontr.h
--- src/support/forkedcontr.h	25 Sep 2002 10:03:41 -0000	1.7
+++ src/support/forkedcontr.h	24 Oct 2002 20:36:20 -0000
@@ -30,7 +30,7 @@
 #pragma interface
 #endif
 
-class Forkedcall;
+class ForkedBase;
 class Timeout;
 
 class ForkedcallsController : public boost::signals::trackable {
@@ -46,7 +46,11 @@ public:
 	static ForkedcallsController & get();
 
 	/// Add a new child process to the list of controlled processes.
-	void addCall(Forkedcall const & newcall);
+	template<typename T>
+	void addCall(T const & newcall) {
+		startTimeout();
+		push_back(new T(newcall));
+	}
 
 	/** This method is connected to the timer. Every XX ms it is called
 	 *  so that we can check on the status of the children. Those that
@@ -58,8 +62,8 @@ public:
 	/// Return a vector of the pids of all the controlled processes.
 	std::vector<pid_t> const getPIDs() const;
 
-	/// Get the command string of the process.
-	string const getCommand(pid_t) const;
+//  	/// Get the command string of the process.
+//  	string const getCommand(pid_t) const;
 
 	/** Kill this process prematurely and remove it from the list.
 	 *  The process is killed within tolerance secs.
@@ -74,8 +78,13 @@ private:
 	///
 	ForkedcallsController(ForkedcallsController const &);
 
+	///
+	void startTimeout();
+	///
+	void push_back(ForkedBase * call);
+
 	/// The child processes
-	typedef std::list<Forkedcall *> ListType;
+	typedef std::list<ForkedBase *> ListType;
 	///
 	ListType forkedCalls;
 

Reply via email to