[rkward-cvs] SF.net SVN: rkward:[3178] branches/2010_10_18_backend_restructuring_branch/ rkward/rbackend

tfry at users.sourceforge.net tfry at users.sourceforge.net
Thu Nov 4 16:26:26 UTC 2010


Revision: 3178
          http://rkward.svn.sourceforge.net/rkward/?rev=3178&view=rev
Author:   tfry
Date:     2010-11-04 16:26:26 +0000 (Thu, 04 Nov 2010)

Log Message:
-----------
Some tweaking, and rework exit strategy.

Modified Paths:
--------------
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rksignalsupport.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp	2010-11-03 18:54:06 UTC (rev 3177)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp	2010-11-04 16:26:26 UTC (rev 3178)
@@ -111,15 +111,6 @@
 SEXP runCommandInternalBase (SEXP pr, RThread::RKWardRError *error);
 
 // ############## R Standard callback overrides BEGIN ####################
-void RSuicide (const char* message) {
-	RK_TRACE (RBACKEND);
-
-	RBackendRequest request (true, RBackendRequest::BackendExit);
-	request.params["message"] = QVariant (i18n ("The R engine has encountered a fatal error:\n%1").arg (message));
-	RThread::this_pointer->handleRequest (&request);
-	RThread::this_pointer->killed = true;
-}
-
 Rboolean RKToplevelStatementFinishedCallback (SEXP expr, SEXP value, Rboolean succeeded, Rboolean visible, void *) {
 	RK_TRACE (RBACKEND);
 	Q_UNUSED (expr);
@@ -319,7 +310,7 @@
 	RK_TRACE (RBACKEND);
 
 	// output while nothing else is running (including handlers?) -> This may be a syntax error.
-	if ((RThread::repl_status.eval_depth == 0) && (!RThread::repl_status.in_browser_context) && (!RThread::this_pointer->killed)) {
+	if ((RThread::repl_status.eval_depth == 0) && (!RThread::repl_status.in_browser_context) && (!RThread::this_pointer->isKilled ())) {
 		if (RThread::repl_status.user_command_status == RThread::RKReplStatus::UserCommandTransmitted) {
 			// status UserCommandTransmitted might have been set from RKToplevelStatementFinishedHandler, too, in which case all is fine
 			// (we're probably inside another task handler at this point, then)
@@ -345,6 +336,14 @@
 void RCleanUp (SA_TYPE saveact, int status, int RunLast) {
 	RK_TRACE (RBACKEND);
 
+	if (RThread::this_pointer->killed == RThread::AlreadyDead) return;	// Nothing to clean up
+
+	// we could be in a signal handler, and the stack base may have changed.
+	uintptr_t old_lim = R_CStackLimit;
+	R_CStackLimit = (uintptr_t)-1;
+
+	if ((status != 0) && (RThread::this_pointer->killed != RThread::ExitNow)) RThread::this_pointer->killed = RThread::EmergencySaveThenExit;
+
 	if (saveact != SA_SUICIDE) {
 		if (!RThread::this_pointer->isKilled ()) {
 			RBackendRequest request (true, RBackendRequest::BackendExit);
@@ -357,17 +356,56 @@
 		R_RunExitFinalizers ();
 		R_CleanTempDir ();
 	}
-	RThread::this_pointer->killed = true;	// just in case
+
+	RThread::this_pointer->r_running = false;	// To signify we have finished everything else and are now trying to create an emergency save (if applicable)
+
+	if (RThread::this_pointer->killed == RThread::EmergencySaveThenExit) {
+		if (R_DirtyImage) R_SaveGlobalEnvToFile (RKCommonFunctions::getUseableRKWardSavefileName ("rkward_recover", ".RData").toLocal8Bit ());
+	}
+
+	RThread::this_pointer->killed = RThread::AlreadyDead;	// just in case
+
+	R_CStackLimit = old_lim;	// well, it should not matter any longer, but...
 }
 
+void RSuicide (const char* message) {
+	RK_TRACE (RBACKEND);
+
+	if (!RThread::this_pointer->isKilled ()) {
+		RBackendRequest request (true, RBackendRequest::BackendExit);
+		request.params["message"] = QVariant (i18n ("The R engine has encountered a fatal error:\n%1").arg (message));
+		RThread::this_pointer->handleRequest (&request);
+		RThread::this_pointer->killed = RThread::EmergencySaveThenExit;
+		RCleanUp (SA_SUICIDE, 1, 0);
+	} else {
+		RK_ASSERT (false);
+	}
+}
+
 void RThread::tryToDoEmergencySave () {
 	RK_TRACE (RBACKEND);
 
-	// we're probably in a signal handler, and the stack base has changed.
-	uintptr_t old_lim = R_CStackLimit;
-	R_CStackLimit = (uintptr_t)-1;
-	if (R_DirtyImage) R_SaveGlobalEnvToFile (RKCommonFunctions::getUseableRKWardSavefileName ("rkward_recover", ".RData").toLocal8Bit ());
-	R_CStackLimit = old_lim;
+	if (inRThread ()) {
+		// If we are in the correct thread, things are easy:
+		RCleanUp (SA_SUICIDE, 1, 0);
+		RK_doIntr ();	// to jump out of the loop, if needed
+	} else {
+		// If we are in the wrong thread, things are a lot more tricky. We need to cause the R thread to exit, and wait for it to finish saving.
+		// Fortunately, if we are in the wrong thread, that probably means, the R thread did *not* crash, and will thus still be functional
+		this_pointer->killed = EmergencySaveThenExit;
+		this_pointer->interruptProcessing (true);
+		for (int i = 0; i < 100; ++i) {		// give it up to ten seconds to intterrupt and exit the loop
+			if (!this_pointer->r_running) break;
+			msleep (100);
+		}
+		if (!this_pointer->r_running) {
+			for (int i = 0; i < 600; ++i) {		// give it up to sixty seconds to finish saving
+				if (this_pointer->killed == AlreadyDead) return;	// finished
+				msleep (100);
+			}
+		}
+		RK_ASSERT (false);	// Too bad, but we seem to be stuck. No chance but to return (and crash)
+	}
 }
 
 QStringList charPArrayToQStringList (const char** chars, int count) {
@@ -651,6 +689,7 @@
 void RThread::processX11Events () {
 	// do not trace
 	if (!this_pointer->r_running) return;
+	if (this_pointer->isKilled ()) return;
 
 	RThread::repl_status.eval_depth++;
 // In case an error (or user interrupt) is caught inside processX11EventsWorker, we don't want to long-jump out.
@@ -662,7 +701,7 @@
 SEXP doError (SEXP call) {
 	RK_TRACE (RBACKEND);
 
-	if ((RThread::repl_status.eval_depth == 0) && (!RThread::repl_status.in_browser_context) && (!RThread::this_pointer->killed)) {
+	if ((RThread::repl_status.eval_depth == 0) && (!RThread::repl_status.in_browser_context) && (!RThread::this_pointer->isKilled ())) {
 		RThread::repl_status.user_command_status = RThread::RKReplStatus::UserCommandFailed;
 	}
 	if (RThread::repl_status.interrupted) {
@@ -965,7 +1004,7 @@
 	if (ctype & RCommand::DirectToOutput) runDirectCommand (".rk.capture.messages()");
 
 	if (ctype & RCommand::QuitCommand) {
-		killed = true;
+		killed = ExitNow;
 	} else if (!(ctype & RCommand::EmptyCommand)) {
 		repl_status.eval_depth++;
 		SEXP parsed = parseCommand (command->command, &error);
@@ -991,9 +1030,6 @@
 	}
 
 	if (ctype & RCommand::DirectToOutput) runDirectCommand (".rk.print.captured.messages()");
-	if (!(ctype & RCommand::Internal)) {
-		if (!RInterface::backendIsLocked () || killed) processX11Events ();
-	}
 
 	// common error/status handling
 	if (error != NoError) {

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h	2010-11-03 18:54:06 UTC (rev 3177)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h	2010-11-04 16:26:26 UTC (rev 3178)
@@ -197,9 +197,16 @@
 		return (r_version >= (1000 * major + 10 * minor + revision));
 	}
 
+/** thread is killed. Should exit as soon as possible. @see kill */
+	enum KillType {
+		NotKilled = 0,
+		ExitNow = 1,
+		EmergencySaveThenExit = 2,
+		AlreadyDead = 3
+	} killed;
 /** "Kills" the thread. Actually this just tells the thread that is is about to be terminated. Allows the thread to terminate gracefully */
-	void kill () { killed = true; };
-	bool isKilled () { return killed; };
+	void kill () { killed = ExitNow; };
+	bool isKilled () { return (killed != NotKilled); };
 
 	QTextCodec *current_locale_codec;
 
@@ -226,8 +233,6 @@
 	static void *default_global_context;
 
 	void commandFinished (bool check_object_updates_needed=true);
-/** thread is killed. Should exit as soon as possible. @see kill */
-	bool killed;
 /** A list of symbols that have been assigned new values during the current command */
 	QStringList changed_symbol_names;
 	static bool inRThread () { return (currentThread () == this_pointer); };

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp	2010-11-03 18:54:06 UTC (rev 3177)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp	2010-11-04 16:26:26 UTC (rev 3178)
@@ -137,19 +137,6 @@
 	return (idle);
 }
 
-bool RInterface::backendIsLocked () {
-	return (RKGlobals::rInterface ()->locked != 0);
-}
-
-void RInterface::tryToDoEmergencySave () {
-	RK_TRACE (RBACKEND);
-	if (!RThread::inRThread ()) {
-		RKGlobals::rInterface ()->r_thread->terminate ();
-		RKGlobals::rInterface ()->r_thread->wait (1000);
-	}
-	RKGlobals::rInterface ()->r_thread->tryToDoEmergencySave ();
-}
-
 void RInterface::startThread () {
 	RK_TRACE (RBACKEND);
 

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h	2010-11-03 18:54:06 UTC (rev 3177)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h	2010-11-04 16:26:26 UTC (rev 3178)
@@ -19,7 +19,6 @@
 #define RINTERFACE_H
 
 #include <qobject.h>
-#include <qmutex.h>
 #include <QFile>
 
 #include "rcommand.h"
@@ -29,7 +28,6 @@
 class RKWardMainWindow;
 class QTimer;
 class RThread;
-struct RKWardStartupOptions;
 struct RBackendRequest;
 
 /** This class provides the main interface to the R-processor.
@@ -74,10 +72,6 @@
 
 	bool backendIsDead ();
 	bool backendIsIdle ();
-
-	static bool backendIsLocked ();
-
-	static void tryToDoEmergencySave ();
 private slots:
 /** called periodically to flush output buffer in RThread */
 	void flushOutput ();

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rksignalsupport.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rksignalsupport.cpp	2010-11-03 18:54:06 UTC (rev 3177)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rksignalsupport.cpp	2010-11-04 16:26:26 UTC (rev 3178)
@@ -20,7 +20,6 @@
 #include <signal.h>
 
 #include "rembedinternal.h"
-#include "rinterface.h"
 
 #include "../debug.h"
 
@@ -70,7 +69,7 @@
 			RK_ASSERT (signum == SIGSEGV);
 		}
 
-		RInterface::tryToDoEmergencySave ();
+		RThread::tryToDoEmergencySave ();
 
 		// if we are not in the R thread, handling the signal in R does more harm than good.
 		if (RThread::inRThread ()) {

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp	2010-11-03 18:54:06 UTC (rev 3177)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp	2010-11-04 16:26:26 UTC (rev 3178)
@@ -45,7 +45,7 @@
 void RThread::run () {
 	RK_TRACE (RBACKEND);
 	thread_id = currentThreadId ();
-	killed = false;
+	killed = NotKilled;
 	previous_command = 0;
 
 	initialize ();
@@ -91,7 +91,7 @@
 		if (killed) return 0;
 		// NOTE: processX11Events() may, conceivably, lead to new requests, which may also wait for sub-commands!
 		processX11Events ();
-		if (!request->done) msleep (10);
+		if (!request->done) msleep (1);
 	}
 
 	RCommandProxy* command = request->command;
@@ -125,6 +125,7 @@
 void RThread::waitIfOutputBufferExceeded () {
 	// don't trace
 	while (out_buf_len > MAX_BUF_LENGTH) {
+		if (isKilled ()) return;	// don't block. Frontend could be crashed
 		msleep (10);
 	}
 }


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list