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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Fri Oct 22 19:08:59 UTC 2010


Revision: 3138
          http://rkward.svn.sourceforge.net/rkward/?rev=3138&view=rev
Author:   tfry
Date:     2010-10-22 19:08:58 +0000 (Fri, 22 Oct 2010)

Log Message:
-----------
Brute force merging of REmbedInternal and RThread classes

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/rthread.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.h

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp	2010-10-22 12:27:35 UTC (rev 3137)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.cpp	2010-10-22 19:08:58 UTC (rev 3138)
@@ -18,7 +18,7 @@
 #include "rembedinternal.h"
 
 // static
-REmbedInternal *REmbedInternal::this_pointer = 0; 
+RThread *RThread::this_pointer = 0; 
 
 #include <qstring.h>
 #include <QStringList>
@@ -31,7 +31,7 @@
 #include "rklocalesupport.h"
 #include "rkpthreadsupport.h"
 #include "rksignalsupport.h"
-#include "rinterface.h"		// for acces to the mutex
+#include "rinterface.h"		// for access to the mutex
 #include "../misc/rkcommonfunctions.h"
 
 #include <stdlib.h>
@@ -116,8 +116,8 @@
 QString SEXPToString (SEXP from_exp);
 int *SEXPToIntArray (SEXP from_exp, unsigned int *count);
 int SEXPToInt (SEXP from_exp, int def_value = INT_MIN);
-SEXP parseCommand (const QString &command_qstring, REmbedInternal::RKWardRError *error);
-SEXP runCommandInternalBase (SEXP pr, REmbedInternal::RKWardRError *error);
+SEXP parseCommand (const QString &command_qstring, RThread::RKWardRError *error);
+SEXP runCommandInternalBase (SEXP pr, RThread::RKWardRError *error);
 
 // ############## R Standard callback overrides BEGIN ####################
 void RSuicide (const char* message) {
@@ -126,8 +126,8 @@
 	RCallbackArgs args;
 	args.type = RCallbackArgs::RBackendExit;
 	args.params["message"] = QVariant (i18n ("The R engine has encountered a fatal error:\n%1").arg (message));
-	REmbedInternal::this_pointer->handleStandardCallback (&args);
-	REmbedInternal::this_pointer->shutdown (true);
+	RThread::this_pointer->handleStandardCallback (&args);
+	RThread::this_pointer->shutdown (true);
 	Rf_error ("Backend dead");	// this jumps us out of the REPL.
 }
 
@@ -164,15 +164,15 @@
 	args.params["prompt"] = QVariant (prompt);
 	args.params["cancelled"] = QVariant (false);
 
-	REmbedInternal::this_pointer->handleStandardCallback (&args);
+	RThread::this_pointer->handleStandardCallback (&args);
 // default implementation seems to return 1 on success, 0 on failure, contrary to some documentation. see unix/std-sys.c
 	if (args.params["cancelled"].toBool ()) {
-		if (REmbedInternal::this_pointer->current_command) REmbedInternal::this_pointer->current_command->status |= RCommand::Canceled;
+		if (RThread::this_pointer->current_command) RThread::this_pointer->current_command->status |= RCommand::Canceled;
 		RK_doIntr();
 		return 0;	// we should not ever get here, but still...
 	}
 	if (buf) {
-		QByteArray localres = REmbedInternal::this_pointer->current_locale_codec->fromUnicode (args.params["result"].toString ());
+		QByteArray localres = RThread::this_pointer->current_locale_codec->fromUnicode (args.params["result"].toString ());
 		// need to append a newline, here. TODO: theoretically, RReadConsole comes back for more, if \0 was encountered before \n.
 		qstrncpy ((char *) buf, localres.left (buflen - 2).append ('\n').data (), buflen);
 		return 1;
@@ -189,7 +189,7 @@
 void RWriteConsoleEx (const char *buf, int buflen, int type) {
 	RK_TRACE (RBACKEND);
 
-	REmbedInternal::this_pointer->handleOutput (REmbedInternal::this_pointer->current_locale_codec->toUnicode (buf, buflen), buflen, type == 0);
+	RThread::this_pointer->handleOutput (RThread::this_pointer->current_locale_codec->toUnicode (buf, buflen), buflen, type == 0);
 }
 
 /** For R callbacks that we want to disable, entirely */
@@ -204,7 +204,7 @@
 		RCallbackArgs args;
 		args.type = RCallbackArgs::RBackendExit;
 		args.params["message"] = QVariant (i18n ("The R engine has shut down with status: %1").arg (status));
-		REmbedInternal::this_pointer->handleStandardCallback (&args);
+		RThread::this_pointer->handleStandardCallback (&args);
 
 		if(saveact == SA_DEFAULT) saveact = SA_SAVE;
 		if (saveact == SA_SAVE) {
@@ -214,14 +214,14 @@
 				if (RunLast) R_dot_Last ();
 		}
 
-		REmbedInternal::this_pointer->shutdown (false);
+		RThread::this_pointer->shutdown (false);
 	} else {
-		REmbedInternal::this_pointer->shutdown (true);
+		RThread::this_pointer->shutdown (true);
 	}
 	Rf_error ("Backend dead");	// this jumps us out of the REPL.
 }
 
-void REmbedInternal::tryToDoEmergencySave () {
+void RThread::tryToDoEmergencySave () {
 	RK_TRACE (RBACKEND);
 
 	// we're probably in a signal handler, and the stack base has changed.
@@ -247,9 +247,9 @@
 	args.type = RCallbackArgs::RChooseFile;
 	args.params["new"] = QVariant ((bool) isnew);
 
-	REmbedInternal::this_pointer->handleStandardCallback (&args);
+	RThread::this_pointer->handleStandardCallback (&args);
 
-	QByteArray localres = REmbedInternal::this_pointer->current_locale_codec->fromUnicode (args.params["result"].toString ());
+	QByteArray localres = RThread::this_pointer->current_locale_codec->fromUnicode (args.params["result"].toString ());
 	qstrncpy ((char *) buf, localres.data (), len);
 
 // return length of filename (strlen (buf))
@@ -275,7 +275,7 @@
 	args.params["titles"] = QVariant (titles);
 	args.params["wtitle"] = QVariant (wtitle);
 
-	REmbedInternal::this_pointer->handleStandardCallback (&args);
+	RThread::this_pointer->handleStandardCallback (&args);
 }
 
 int REditFiles (int nfile, const char **file, const char **title, const char *wtitle) {
@@ -358,7 +358,7 @@
 	args.params["button_cancel"] = QVariant (button_cancel);
 	if (wait) args.params["wait"] = "1";
 
-	REmbedInternal::this_pointer->handleStandardCallback (&args);
+	RThread::this_pointer->handleStandardCallback (&args);
 
 	QString ret = args.params["result"].toString ();
 	if (ret == "yes") return 1;
@@ -401,17 +401,30 @@
 
 // ############## R Standard callback overrides END ####################
 
-char *REmbedInternal::na_char_internal = new char;
+char *RThread::na_char_internal = new char;
 
-REmbedInternal::REmbedInternal () {
+RThread::RThread () {
 	RK_TRACE (RBACKEND);
 
 	current_locale_codec = QTextCodec::codecForLocale ();
 	r_running = false;
+
+	current_command = 0;
+
+	RK_ASSERT (this_pointer == 0);
+	this_pointer = this;
+	current_output = 0;
+	out_buf_len = 0;
+	output_paused = false;
+
+#ifdef Q_WS_WIN
+	// we hope that on other platforms the default is reasonable
+	setStackSize (0xa00000);	// 10MB as recommended by r_exts-manual
+#endif
 }
 
 #ifdef Q_WS_WIN
-void REmbedInternal::setupCallbacks () {
+void RThread::setupCallbacks () {
 	RK_TRACE (RBACKEND);
 
 	R_setStartTime();
@@ -436,16 +449,16 @@
 	RK_R_Params.R_Interactive = (Rboolean) 1;
 }
 
-void REmbedInternal::connectCallbacks () {
+void RThread::connectCallbacks () {
 	RK_TRACE (RBACKEND);
 	R_SetParams(&RK_R_Params);
 }
 #else
-void REmbedInternal::setupCallbacks () {
+void RThread::setupCallbacks () {
 	RK_TRACE (RBACKEND);
 }
 
-void REmbedInternal::connectCallbacks () {
+void RThread::connectCallbacks () {
 	RK_TRACE (RBACKEND);
 
 // IMPORTANT: see also the #ifdef QS_WS_WIN-portion!
@@ -474,11 +487,11 @@
 }
 #endif
 
-REmbedInternal::~REmbedInternal () {
+RThread::~RThread () {
 	RK_TRACE (RBACKEND);
 }
 
-void REmbedInternal::shutdown (bool suicidal) {
+void RThread::shutdown (bool suicidal) {
 	RK_TRACE (RBACKEND);
 
 	if (!r_running) return;		// already shut down
@@ -522,7 +535,7 @@
 #endif
 }
 
-void REmbedInternal::processX11Events () {
+void RThread::processX11Events () {
 	// do not trace
 	if (!this_pointer->r_running) return;
 
@@ -574,7 +587,7 @@
 				} else if (IS_LATIN1 (dummy)) {
 					list[i] = QString::fromLatin1 ((char *) STRING_PTR (dummy));
 				} else {
-					list[i] = REmbedInternal::this_pointer->current_locale_codec->toUnicode ((char *) STRING_PTR (dummy));
+					list[i] = RThread::this_pointer->current_locale_codec->toUnicode ((char *) STRING_PTR (dummy));
 				}
 			}
 		}
@@ -705,7 +718,7 @@
 
 	unsigned int count;
 	QString *strings = SEXPToStringList (call, &count);
-	REmbedInternal::this_pointer->handleError (strings, count);
+	RThread::this_pointer->handleError (strings, count);
 	delete [] strings;
 	return R_NilValue;
 }
@@ -714,7 +727,7 @@
 SEXP doCondition (SEXP call) {
 	int count;
 	char **strings = extractStrings (call, &count);
-	REmbedInternal::this_pointer->handleCondition (strings, count);
+	RThread::this_pointer->handleCondition (strings, count);
 	return R_NilValue;
 } */
 
@@ -727,7 +740,7 @@
 	for (unsigned int i = 0; i < count; ++i) {
 		list.append (strings[i]);
 	}
-	REmbedInternal::this_pointer->handleSubstackCall (list);
+	RThread::this_pointer->handleSubstackCall (list);
 	delete [] strings;
 	return R_NilValue;
 }
@@ -740,8 +753,8 @@
 	RK_TRACE (RBACKEND);
 
 	RK_DO (qDebug ("Changing locale"), RBACKEND, DL_WARNING);
-	REmbedInternal::this_pointer->current_locale_codec = RKGetCurrentLocaleCodec ();
-	RK_DO (qDebug ("New locale codec is %s", REmbedInternal::this_pointer->current_locale_codec->name ().data ()), RBACKEND, DL_WARNING);
+	RThread::this_pointer->current_locale_codec = RKGetCurrentLocaleCodec ();
+	RK_DO (qDebug ("New locale codec is %s", RThread::this_pointer->current_locale_codec->name ().data ()), RBACKEND, DL_WARNING);
 
 	return R_NilValue;
 }
@@ -750,10 +763,10 @@
 SEXP doLocaleName () {
 	RK_TRACE (RBACKEND);
 
-	RK_ASSERT (REmbedInternal::this_pointer->current_locale_codec);
+	RK_ASSERT (RThread::this_pointer->current_locale_codec);
 	SEXP res = Rf_allocVector(STRSXP, 1);
 	PROTECT (res);
-	SET_STRING_ELT (res, 0, Rf_mkChar (REmbedInternal::this_pointer->current_locale_codec->name ().data ()));
+	SET_STRING_ELT (res, 0, Rf_mkChar (RThread::this_pointer->current_locale_codec->name ().data ()));
 	UNPROTECT (1);
 	return res;
 }
@@ -785,7 +798,7 @@
 	return (R_NilValue);
 }
 
-bool REmbedInternal::startR (int argc, char** argv, bool stack_check) {
+bool RThread::startR (int argc, char** argv, bool stack_check) {
 	RK_TRACE (RBACKEND);
 
 	setupCallbacks ();
@@ -877,13 +890,13 @@
 	return true;
 }
 
-SEXP parseCommand (const QString &command_qstring, REmbedInternal::RKWardRError *error) {
+SEXP parseCommand (const QString &command_qstring, RThread::RKWardRError *error) {
 	RK_TRACE (RBACKEND);
 
 	ParseStatus status = PARSE_NULL;
 	SEXP cv, pr;
 
-	QByteArray localc = REmbedInternal::this_pointer->current_locale_codec->fromUnicode (command_qstring);		// needed so the string below does not go out of scope
+	QByteArray localc = RThread::this_pointer->current_locale_codec->fromUnicode (command_qstring);		// needed so the string below does not go out of scope
 	const char *command = localc.data ();
 
 	PROTECT(cv=Rf_allocVector(STRSXP, 1));
@@ -903,13 +916,13 @@
 
 	if (status != PARSE_OK) {
 		if ((status == PARSE_INCOMPLETE) || (status == PARSE_EOF)) {
-			*error = REmbedInternal::Incomplete;
+			*error = RThread::Incomplete;
 		} else if (status == PARSE_ERROR) {
 			//extern SEXP parseError (SEXP call, int linenum);
 			//parseError (R_NilValue, 0);
-			*error = REmbedInternal::SyntaxError;
+			*error = RThread::SyntaxError;
 		} else { // PARSE_NULL
-			*error = REmbedInternal::OtherError;
+			*error = RThread::OtherError;
 		}
 		pr = R_NilValue;
 	}
@@ -917,7 +930,7 @@
 	return pr;
 }
 
-SEXP runCommandInternalBase (SEXP pr, REmbedInternal::RKWardRError *error) {
+SEXP runCommandInternalBase (SEXP pr, RThread::RKWardRError *error) {
 	RK_TRACE (RBACKEND);
 
 	SEXP exp;
@@ -941,9 +954,9 @@
 	}
 
 	if (r_error) {
-		*error = REmbedInternal::OtherError;
+		*error = RThread::OtherError;
 	} else {
-		*error = REmbedInternal::NoError;
+		*error = RThread::NoError;
 	}
 
 	UNPROTECT(1); /* pr */
@@ -969,7 +982,7 @@
 //TODO: I don't think it's meant to be this way. Maybe nag the R-devels about it one day. 
 //TODO: this is not entirely correct. See PrintValueEnv (), which is what Repl_Console uses (but is hidden)
 */
-void tryPrintValue (SEXP exp, REmbedInternal::RKWardRError *error) {
+void tryPrintValue (SEXP exp, RThread::RKWardRError *error) {
 	RK_TRACE (RBACKEND);
 
 	int ierror = 0;
@@ -986,9 +999,9 @@
 	UNPROTECT (2);	/* e, tryprint */
 
 	if (ierror) {
-		*error = REmbedInternal::OtherError;
+		*error = RThread::OtherError;
 	} else {
-		*error = REmbedInternal::NoError;
+		*error = RThread::NoError;
 	}
 }
 #endif
@@ -1008,12 +1021,12 @@
 	} while (((repldll_result = R_ReplDLLdo1 ()) == 2) && (!repldll_buffer_transfer_finished));	// keep iterating while the statement is incomplete, and we still have more in the buffer to transfer
 	//Rprintf ("iteration complete, status: %d\n", repldll_result);
 	PROTECT (R_LastvalueSymbol);		// why do we need this? No idea, but R_ToplevelExec tries to unprotect something
-	if (REmbedInternal::this_pointer->RRuntimeIsVersion (2, 11, 9)) {
+	if (RThread::this_pointer->RRuntimeIsVersion (2, 11, 9)) {
 		PROTECT (R_LastvalueSymbol);		// ... and with R 2.12.0 it tries to unprotect two things
 	}
 }
 
-bool REmbedInternal::runDirectCommand (const QString &command) {
+bool RThread::runDirectCommand (const QString &command) {
 	RK_TRACE (RBACKEND);
 
 	RCommand c (command, RCommand::App | RCommand::Sync | RCommand::Internal);
@@ -1021,7 +1034,7 @@
 	return (c.succeeded ());
 }
 
-RCommand *REmbedInternal::runDirectCommand (const QString &command, RCommand::CommandTypes datatype) {
+RCommand *RThread::runDirectCommand (const QString &command, RCommand::CommandTypes datatype) {
 	RK_TRACE (RBACKEND);
 	RK_ASSERT ((datatype >= RCommand::GetIntVector) && (datatype <= RCommand::GetStructuredData));
 
@@ -1030,7 +1043,7 @@
 	return c;
 }
 
-void REmbedInternal::runCommand (RCommand *command) {
+void RThread::runCommand (RCommand *command) {
 	RK_TRACE (RBACKEND);
 	RK_ASSERT (command);
 
@@ -1087,15 +1100,15 @@
 		}
 		if (ok == FALSE) {
 			if (repldll_last_parse_successful) {
-				error = REmbedInternal::OtherError;
+				error = RThread::OtherError;
 			} else {
-				error = REmbedInternal::SyntaxError;
+				error = RThread::SyntaxError;
 			}
 		} else {
 			if (prev_iteration_was_incomplete) {
-				error = REmbedInternal::Incomplete;
+				error = RThread::Incomplete;
 			} else {
-				error = REmbedInternal::NoError;
+				error = RThread::NoError;
 			}
 		}
 		repldlldo1_wants_code = false;		// make sure we don't get confused in RReadConsole

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h	2010-10-22 12:27:35 UTC (rev 3137)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h	2010-10-22 19:08:58 UTC (rev 3138)
@@ -22,8 +22,12 @@
 
 #include <QMap>
 #include <QVariant>
+#include <QThread>
+#include <QStringList>
+#include <QEvent>
 
 #include "rcommand.h"
+#include "rcommandstack.h"
 
 #ifdef Q_WS_WIN
 extern "C" {
@@ -53,26 +57,89 @@
 
 class QStringList;
 class QTextCodec;
+class RInterface;
+struct RCallbackArgs;
+struct ROutput;
 
- /** The main purpose of separating this class from RThread is that R- and Qt-includes don't go together well. Hence this class is Qt-agnostic while
-	RThread is essentially R-agnostic.
-	
-	@see RThread
+/** this struct is used to pass on eval-requests (i.e. request for RKWard to do something, which may involve issuing further commands) from the
+backend-thread to the main thread. Do not use outside the backend-classes. */
+struct REvalRequest {
+private:
+friend class RInterface;
+friend class RThread;
+	QStringList call;
+	RCommandChain *in_chain;
+};
 
-	*@author Thomas Friedrichsmeier
+/** Simple event class to relay information from the RThread to the main thread. This is basically like QCustomEvent in Qt3*/
+class RKRBackendEvent : public QEvent {
+public:
+	enum EventType {
+		Base = QEvent::User + 1,
+		RCommandIn,
+		RCommandOut,
+		RBusy,
+		RIdle,
+		RCommandOutput,
+		RStarted,
+		REvalRequest,
+		RCallbackRequest,
+		RStartupError
+	};
+
+	RKRBackendEvent (EventType type, void* data=0) : QEvent ((QEvent::Type) type) { _data = data; };
+	RKRBackendEvent ();
+
+	EventType etype () { return ((EventType) type ()); };
+	void* data () { return _data; };
+private:
+	void* _data;
+};
+
+/** This class represents the thread the R backend is running in. So to speak, this is where the "eventloop" of R is running. The main thing happening
+in this class, is that an infinite loop is running. Whenever there are commands to be executed, those get evaluated. Also, at regular intervals,
+processing of X11-Events in R is triggered. The rest of the time the thread sleeps.
+
+Actually, there are really two copies of the main loop: The regular one, and a second one which gets run when the R backend has requested some
+task to be carried out (@see handleSubstackCall). In this case, we might have to run some further child commands in the backend, before we proceed with the commands in
+the main queque. Some thing like:
+
+- Run some RCommand s
+	- R backend asks for some information / action
+		- potentially some more RCommand s are needed to accomplish this request
+			- (additional levels of substacks)
+		- return the result
+	- R backend request completed
+- Run some more RCommand s
+
+This subordinate/nested eventloop is done in handleSubstackCall ().
+
+A closely related class is RInterface: RThread communicates with RInterface by placing QCustomEvent s, when commands are done
+or when the backend needs information from the frontend. For historical reasons, the definitions of RThread class-members are currently spread over different files.
+
+Only one RThread-object can be used in an application.
+Don't use this class in RKWard directly. Unless you really want to modify the internal workings of the backend, you will want to look at RInterface and use the functions there.
+
+ at see RInterface
+
+ at author Thomas Friedrichsmeier
 */
-class REmbedInternal {
+class RThread : public QThread {
 public: 
-/** constructor. You can't create an instance of this class due to pure virtual functions. Create an instance of RThread instead. */
-	REmbedInternal ();
+/** constructor. Only one RThread should ever be created, and that happens in RInterface::RInterface (). */
+	RThread ();
 /** destructor */
-	virtual ~REmbedInternal ();
+	virtual ~RThread ();
 
-/** set up R standard callbacks */
-	void setupCallbacks ();
-/** connect R standard callbacks */
-	void connectCallbacks ();
+/** Pause output by placing it in a delay loop, until unpaused again */
+	void pauseOutput (bool paused) { output_paused = paused; };
+/** the internal counterpart to pauseOutput () */
+	void waitIfOutputPaused ();
 
+
+/** interrupt processing of the current command. This is much like the user pressing Ctrl+C in a terminal with R. This is probably the only non-portable function in RThread, but I can't see a good way around placing it here, or to make it portable. */
+	void interruptProcessing (bool interrupt);
+
 /** Enum specifying types of errors that may occur while parsing/evaluating a command in R */
 	enum RKWardRError {
 		NoError=0,			/**< No error */
@@ -81,6 +148,18 @@
 		OtherError=3		/**< Other error, usually a semantic error, e.g. object not found */
 	};
 
+/** An enum describing whether initialization of the embedded R-process went well, or what errors occurred. */
+	enum InitStatus {
+		Ok=0,					/**< No error */
+		LibLoadFail=1,		/**< Error while trying to load the rkward R package */
+		SinkFail=2,			/**< Error while redirecting R's stdout and stderr to files to be read from rkward */
+		OtherFail=4			/**< Other error while initializing the embedded R-process */
+	}; // TODO: make obsolete!
+
+/** initializes the R-backend. Returns an error-code that consists of a bit-wise or-conjunction of the RThread::InitStatus -enum, RThread::Ok on success.
+Note that you should call initialize only once in a application */
+	int initialize ();
+
 /** clean shutdown of R.
 @param suicidal if true, perform only the most basic shutdown operations */
 	void shutdown (bool suicidal);
@@ -104,36 +183,45 @@
 /** call this periodically to make R's x11 windows process their events */
 	static void processX11Events ();
 
+/** convenience struct for event passing */
+	struct ROutputContainer {
+		/** the actual output fragment */
+		ROutput *output;
+		/** the corresponding command */
+		RCommand *command;
+	};
+/** current output */
+	ROutput *current_output;
+/** current length of output. Used so we can flush every once in a while, if output becomes too long */
+	int out_buf_len;
+
 /** This gets called on normal R output (R_WriteConsole). Used to get at output. */
-	virtual void handleOutput (const QString &output, int len, bool regular) = 0;
+	void handleOutput (const QString &output, int len, bool regular);
 
-/** This gets called, when the console is flushed */
-	virtual void flushOutput () = 0;
+/** Flushes current output buffer. Lock the mutex before calling this function! It is called from both threads and is not re-entrant */
+	void flushOutput ();
 
-/** This gets called, when R reports warnings/messages. Used to get at warning-output. */
-//	virtual void handleCondition (char **call, int call_length) = 0;
+/** This gets called, when R reports an error (override of options ("error") in R). Used to get at error-output.
+This function is public for technical reasons, only. Don't use except from R-backend code!
+reports an error. */
+	void handleError (QString *call, int call_length);
 
-/** This gets called, when R reports an error (override of options ("error") in R). Used to get at error-output. */
-	virtual void handleError (QString *call, int call_length) = 0;
+/** This is a sub-eventloop, being run when the backend request information from the frontend. See \ref RThread for a more detailed description */
+	void handleSubstackCall (QStringList &call);
 
-/** The main callback from R to rkward. Since we need QStrings and stuff to handle the requests, this is only a pure virtual function. The real
-implementation is in RThread::handleSubstackCall () */
-	virtual void handleSubstackCall (QStringList &list) = 0;
+/** This is a minimal sub-eventloop, being run, when the backend requests simple information from the frontend. It differs from handleSubstack in two
+points:
+1) it does not create a full-fledged substack for additional R commands
+2) it may return information via the args parameter immediately */
+	void handleStandardCallback (RCallbackArgs *args);
 
-/** This second callback handles R standard callbacks. The difference to the first one is, that these are typically required to finish within the same
-function. On the other hand, also, they don't require further computations in R, and hence no full-fledged substack.
-
-Otherwise it is very similar to handleSubstackCall (), esp. in that is implemented in RThread::handleStandardCallback ()
- at see RCallbackArgs @see RCallbackType */
-	virtual void handleStandardCallback (RCallbackArgs *args) = 0;
-
 /** The command currently being executed. */
 	RCommand *current_command;
 
 	void runCommand (RCommand *command);
 
 /** only one instance of this class may be around. This pointer keeps the reference to it, for interfacing to from C to C++ */
-	static REmbedInternal *this_pointer;
+	static RThread *this_pointer;
 	static char *na_char_internal;
 	static void tryToDoEmergencySave ();
 	bool r_running;
@@ -166,12 +254,34 @@
 	int locked;
 /** thread is killed. Should exit as soon as possible. @see kill */
 	bool killed;
+/** On pthread systems this is the pthread_id of the backend thread. It is needed to send SIGINT to the R backend */
+	Qt::HANDLE thread_id;
+private:
+/** set up R standard callbacks */
+	void setupCallbacks ();
+/** connect R standard callbacks */
+	void connectCallbacks ();
+
+	int r_version;
+protected:
+/** the main loop. See \ref RThread for a more detailed description */
+	void run ();
+private:
+/** This is the function in which an RCommand actually gets processed. Basically it passes the command to runCommand () and sends RInterface some events about what is currently happening. */
+	void doCommand (RCommand *command);
+	void notifyCommandDone (RCommand *command);
 /** The internal storage for pauseOutput () */
 	bool output_paused;
-private:
-	int r_version;
-// can't declare this as part of the class, as it would confuse REmbed
-//	SEXPREC *runCommandInternalBase (const char *command, bool *error);
+
+/** A copy of the names of the toplevel environments (as returned by "search ()"). */
+	QStringList toplevel_env_names;
+/** A copy of the names of the toplevel symbols in the .GlobalEnv. */
+	QStringList global_env_toplevel_names;
+/** A list of symbols that have been assigned new values during the current command */
+	QStringList changed_symbol_names;
+/** check wether the object list / global environment / individual symbols have changed, and updates them, if needed */
+	void checkObjectUpdatesNeeded (bool check_list);
+	QList<RCommand*> all_current_commands;
 };
  
 #endif

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp	2010-10-22 12:27:35 UTC (rev 3137)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp	2010-10-22 19:08:58 UTC (rev 3138)
@@ -17,7 +17,7 @@
 
 #include "rinterface.h"
 
-#include "rthread.h"
+#include "rembedinternal.h"
 #include "rcommandstack.h"
 #include "../rkward.h"
 #include "../settings/rksettingsmoduler.h"

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp	2010-10-22 12:27:35 UTC (rev 3137)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp	2010-10-22 19:08:58 UTC (rev 3138)
@@ -14,7 +14,7 @@
  *   (at your option) any later version.                                   *
  *                                                                         *
  ***************************************************************************/
-#include "rthread.h"
+#include "rembedinternal.h"
 
 #include "rinterface.h"
 #include "rcommandstack.h"
@@ -42,27 +42,6 @@
 
 #define MAX_BUF_LENGTH 4000
 
-RThread::RThread () : QThread (), REmbedInternal () {
-	RK_TRACE (RBACKEND);
-	current_command = 0;
-
-	RK_ASSERT (this_pointer == 0);
-	this_pointer = this;
-	RK_ASSERT (this_pointer);
-	current_output = 0;
-	out_buf_len = 0;
-	output_paused = false;
-
-#ifdef Q_WS_WIN
-	// we hope that on other platforms the default is reasonable
-	setStackSize (0xa00000);	// 10MB as recommended by r_exts-manual
-#endif
-}
-
-RThread::~RThread() {
-	RK_TRACE (RBACKEND);
-}
-
 void RThread::interruptProcessing (bool interrupt) {
 	if (!interrupt) return;
 #ifdef Q_WS_WIN

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.h	2010-10-22 12:27:35 UTC (rev 3137)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.h	2010-10-22 19:08:58 UTC (rev 3138)
@@ -17,175 +17,6 @@
 #ifndef RTHREAD_H
 #define RTHREAD_H
 
-#include <qthread.h>
-#include <qstringlist.h>
-#include <QList>
-#include <QEvent>
-#include <QDateTime>
+#error File obsolete
 
-#include "rcommand.h"
-#include "rcommandstack.h"
-#include "rembedinternal.h"
-
-class RInterface;
-struct RCallbackArgs;
-struct ROutput;
-
-/** this struct is used to pass on eval-requests (i.e. request for RKWard to do something, which may involve issuing further commands) from the
-backend-thread to the main thread. Do not use outside the backend-classes. */
-struct REvalRequest {
-private:
-friend class RInterface;
-friend class RThread;
-	QStringList call;
-	RCommandChain *in_chain;
-};
-
-/** Simple event class to relay information from the RThread to the main thread. This is basically like QCustomEvent in Qt3*/
-class RKRBackendEvent : public QEvent {
-public:
-	enum EventType {
-		Base = QEvent::User + 1,
-		RCommandIn,
-		RCommandOut,
-		RBusy,
-		RIdle,
-		RCommandOutput,
-		RStarted,
-		REvalRequest,
-		RCallbackRequest,
-		RStartupError
-	};
-
-	RKRBackendEvent (EventType type, void* data=0) : QEvent ((QEvent::Type) type) { _data = data; };
-	RKRBackendEvent ();
-
-	EventType etype () { return ((EventType) type ()); };
-	void* data () { return _data; };
-private:
-	void* _data;
-};
-
-/** This class represents the thread the R backend is running in. So to speak, this is where the "eventloop" of R is running. The main thing happening
-in this class, is that an infinite loop is running. Whenever there are commands to be executed, those get evaluated. Also, at regular intervals,
-processing of X11-Events in R is triggered. The rest of the time the thread sleeps.
-
-Actually, there are really two copies of the main loop: The regular one, and a second one which gets run when the R backend has requested some
-task to be carried out (@see handleSubstackCall). In this case, we might have to run some further child commands in the backend, before we proceed with the commands in
-the main queque. Some thing like:
-
-- Run some RCommand s
-	- R backend asks for some information / action
-		- potentially some more RCommand s are needed to accomplish this request
-			- (additional levels of substacks)
-		- return the result
-	- R backend request completed
-- Run some more RCommand s
-
-This subordinate/nested eventloop is done in handleSubstackCall ().
-
-A closely related class is RInterface: RThread communicates with RInterface by placing QCustomEvent s, when commands are done
-or when the backend needs information from the frontend. Also RThread and REmbedInternal are only separate for technical reasons (R-includes and Qt-includes clashing).
-
-Only one RThread-object can be used in an application.
-Don't use this class in RKWard directly. Unless you really want to modify the internal workings of the backend, you will want to look at RInterface and use the functions there.
-
- at see RInterface
- at see REmbedInternal
-
- at author Thomas Friedrichsmeier
-*/
-class RThread : public QThread, public REmbedInternal {
-public:
-/** constructor. Only one RThread should ever be created, and that happens in RInterface::RInterface (). */
-	RThread ();
-/** destructor */
-	~RThread ();
-
-/** Pause output by placing it in a delay loop, until unpaused again */
-	void pauseOutput (bool paused) { output_paused = paused; };
-/** the internal counterpart to pauseOutput () */
-	void waitIfOutputPaused ();
-
-/** An enum describing whether initialization of the embedded R-process went well, or what errors occurred. */
-	enum InitStatus {
-		Ok=0,					/**< No error */
-		LibLoadFail=1,		/**< Error while trying to load the rkward R package */
-		SinkFail=2,			/**< Error while redirecting R's stdout and stderr to files to be read from rkward */
-		OtherFail=4			/**< Other error while initializing the embedded R-process */
-	};
-
-/** initializes the R-backend. Returns an error-code that consists of a bit-wise or-conjunction of the RThread::InitStatus -enum, RThread::Ok on success.
-Note that you should call initialize only once in a application */
-	int initialize ();
-
-/** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
-generates standard output. @see REmbedInternal::handleOutput () */
-	void handleOutput (const QString &output, int buf_length, bool regular);
-
-/** Flushes current output buffer. Lock the mutex before calling this function! It is called from both threads and is not re-entrant */
-	void flushOutput ();
-
-/** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
-signals a condition. @see REmbedInternal::handleCondition () */
-//	void handleCondition (char **call, int call_length);
-
-/** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
-reports an error. @see REmbedInternal::handleError () */
-	void handleError (QString *call, int call_length);
-
-/** This function is public for technical reasons, only. Don't use except from REmbedInternal!
-
-This is a sub-eventloop, being run when the backend request information from the frontend. See \ref RThread for a more detailed description
- at see REmbedInternal::handleSubstackCall () */
-	void handleSubstackCall (QStringList &call);
-
-/** This function is public for technical reasons, only. Don't use except from REmbedInternal!
-
-This is a minimal sub-eventloop, being run, when the backend requests simple information from the frontend. It differs from handleSubstack in two
-points:
-1) it does not create a full-fledged substack for additional R commands
-2) it may return information via the args parameter immediately
-
- at see REmbedInternal::handleStandardCallback () */
-	void handleStandardCallback (RCallbackArgs *args);
-
-/** convenience struct for event passing */
-	struct ROutputContainer {
-		/** the actual output fragment */
-		ROutput *output;
-		/** the corresponding command */
-		RCommand *command;
-	};
-/** current output */
-	ROutput *current_output;
-/** current length of output. Used so we can flush every once in a while, if output becomes too long */
-	int out_buf_len;
-
-/** interrupt processing of the current command. This is much like the user pressing Ctrl+C in a terminal with R. This is probably the only non-portable function in RThread, but I can't see a good way around placing it here, or to make it portable. */
-	void interruptProcessing (bool interrupt);
-
-/** On pthread systems this is the pthread_id of the backend thread. It is needed to send SIGINT to the R backend */
-	Qt::HANDLE thread_id;
-protected:
-/** the main loop. See \ref RThread for a more detailed description */
-	void run ();
-private:
-/** This is the function in which an RCommand actually gets processed. Basically it passes the command to REmbedInteranl::runCommandInternal () and sends RInterface some events about what is currently happening. */
-	void doCommand (RCommand *command);
-	void notifyCommandDone (RCommand *command);
-/** The internal storage for pauseOutput () */
-	bool output_paused;
-
-/** A copy of the names of the toplevel environments (as returned by "search ()"). */
-	QStringList toplevel_env_names;
-/** A copy of the names of the toplevel symbols in the .GlobalEnv. */
-	QStringList global_env_toplevel_names;
-/** A list of symbols that have been assigned new values during the current command */
-	QStringList changed_symbol_names;
-/** check wether the object list / global environment / individual symbols have changed, and updates them, if needed */
-	void checkObjectUpdatesNeeded (bool check_list);
-	QList<RCommand*> all_current_commands;
-};
-
 #endif


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