[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