[rkward-cvs] SF.net SVN: rkward-code:[4707] trunk/rkward/rkward/rbackend
tfry at users.sf.net
tfry at users.sf.net
Sun Apr 21 18:26:23 UTC 2013
Revision: 4707
http://sourceforge.net/p/rkward/code/4707
Author: tfry
Date: 2013-04-21 18:26:22 +0000 (Sun, 21 Apr 2013)
Log Message:
-----------
Start implementing "priority commands" (which will be run out-of-execution-order inside R's event loop).
So far the frontend side is done, only (but all dry theory so far; not tested beyond not breaking existing commands).
Modified Paths:
--------------
trunk/rkward/rkward/rbackend/rcommand.h
trunk/rkward/rkward/rbackend/rcommandstack.cpp
trunk/rkward/rkward/rbackend/rinterface.cpp
trunk/rkward/rkward/rbackend/rinterface.h
trunk/rkward/rkward/rbackend/rkrbackendprotocol_frontend.cpp
trunk/rkward/rkward/rbackend/rkrbackendprotocol_frontend.h
trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h
Modified: trunk/rkward/rkward/rbackend/rcommand.h
===================================================================
--- trunk/rkward/rkward/rbackend/rcommand.h 2013-04-21 13:10:07 UTC (rev 4706)
+++ trunk/rkward/rkward/rbackend/rcommand.h 2013-04-21 18:26:22 UTC (rev 4707)
@@ -141,22 +141,24 @@
/** Types of commands (potentially more to come), bitwise or-able,
although partially exclusive. See \ref UsingTheInterfaceToR for a overview of what these are used for. TODO: find out, why Canceled is in here, and document that fact. */
enum CommandTypes {
- User=1, /**< Command was created directly by the user (e.g. in the console or in a command editor window) */
- Plugin=1 << 1, /**< Command comes from a plugin */
- App=1 << 2, /**< Command comes from the application (e.g. loading / saving the workspace */
- Sync=1 << 3, /**< Command is used to sync data to or from R-space. Typically used in the editor classes */
- EmptyCommand=1 << 4, /**< Command is empty and will not be processed (an empty command may be used as a "marker") */
- Console=1 << 5, /**< Command originated in the console. These commands will get some extra treatment in RKwatch */
- Internal=1 << 6, /**< Command is meant to be used in the backend, only. Do not use outside rbackend classes! */
- Silent=1 << 7, /**< Command can be interrupted, but is otherwise an internal command. In particular it should not be carbon copied to the output. */
- GetIntVector=1 << 8, /**< Try to fetch result as an array of integers */
- GetStringVector=1 << 9, /**< Try to fetch result as an array of chars */
- GetRealVector=1 << 10, /**< Try to fetch result as an array of doubles */
- GetStructuredData=1 << 11, /**< Try to fetch result as an RData structure */
- CCOutput=1 << 12, /**< Append command output to the HTML-output file */
- CCCommand=1 << 13, /**< Append the command itself to the HTML-output file */
- ObjectListUpdate=1 << 14, /**< The command may change the list of objects available. Do an update */
- QuitCommand=1 << 15 /**< The R backend should be killed */
+ User=1, /**< Command was created directly by the user (e.g. in the console or in a command editor window) */
+ Plugin=1 << 1, /**< Command comes from a plugin */
+ App=1 << 2, /**< Command comes from the application (e.g. loading / saving the workspace */
+ Sync=1 << 3, /**< Command is used to sync data to or from R-space. Typically used in the editor classes */
+ EmptyCommand=1 << 4, /**< Command is empty and will not be processed (an empty command may be used as a "marker") */
+ Console=1 << 5, /**< Command originated in the console. These commands will get some extra treatment in RKwatch */
+ Internal=1 << 6, /**< Command is meant to be used in the backend, only. Do not use outside rbackend classes! */
+ Silent=1 << 7, /**< Command can be interrupted, but is otherwise an internal command. In particular it should not be carbon copied to the output. */
+ GetIntVector=1 << 8, /**< Try to fetch result as an array of integers */
+ GetStringVector=1 << 9, /**< Try to fetch result as an array of chars */
+ GetRealVector=1 << 10, /**< Try to fetch result as an array of doubles */
+ GetStructuredData=1 << 11, /**< Try to fetch result as an RData structure */
+ CCOutput=1 << 12, /**< Append command output to the HTML-output file */
+ CCCommand=1 << 13, /**< Append the command itself to the HTML-output file */
+ ObjectListUpdate=1 << 14, /**< The command may change the list of objects available. Do an update */
+ QuitCommand=1 << 15, /**< The R backend should be killed */
+ PriorityCommand=1 << 16 /**< The command has high priority, should be run during R's event loop processing. In general, PriorityCommands *must* not have side-effects
+ Use only, when absolutely necessary. */
};
enum CommandStatus {
Running=1, /**< command is currently running */
Modified: trunk/rkward/rkward/rbackend/rcommandstack.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rcommandstack.cpp 2013-04-21 13:10:07 UTC (rev 4706)
+++ trunk/rkward/rkward/rbackend/rcommandstack.cpp 2013-04-21 18:26:22 UTC (rev 4707)
@@ -47,8 +47,17 @@
RK_TRACE (RBACKEND);
RK_ASSERT (parent);
- RCommandStackModel::getModel ()->aboutToAdd (parent, parent->sub_commands.size ());
- parent->sub_commands.append (child);
+ int pos = parent->sub_commands.size ();
+ if (child->is_command && (child->toCommand ()->type () & RCommand::PriorityCommand)) {
+ // Add priority commands before any regular command, after other priority commands. Always in main chain.
+ RK_ASSERT (parent == regular_stack);
+ for (pos = 0; pos < parent->sub_commands.size (); ++pos) {
+ RCommand *com = parent->sub_commands[pos]->toCommand ();
+ if (!(com && (com->type () & RCommand::PriorityCommand))) break;
+ }
+ }
+ RCommandStackModel::getModel ()->aboutToAdd (parent, pos);
+ parent->sub_commands.insert (pos, child);
child->parent = parent;
RCommandStackModel::getModel ()->addComplete ();
}
@@ -91,12 +100,6 @@
RCommand* RCommandStack::currentCommand () {
RK_TRACE (RBACKEND);
- if (RK_Debug_CommandStep) {
- QTime t;
- t.start ();
- while (t.elapsed () < RK_Debug_CommandStep) {}
- }
-
RCommandChain *dummy;
do { // first pop any empty things in the way
dummy = activeSubItemOf (regular_stack);
Modified: trunk/rkward/rkward/rbackend/rinterface.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.cpp 2013-04-21 13:10:07 UTC (rev 4706)
+++ trunk/rkward/rkward/rbackend/rinterface.cpp 2013-04-21 18:26:22 UTC (rev 4707)
@@ -135,22 +135,35 @@
return (RCommandStack::regular_stack->isEmpty() && (!runningCommand()));
}
-RCommand *RInterface::popPreviousCommand () {
+RCommand *RInterface::popPreviousCommand (int id) {
RK_TRACE (RBACKEND);
RK_ASSERT (!all_current_commands.isEmpty ());
- RCommand *ret = all_current_commands.takeLast ();
- RCommandStack::pop (ret);
- return ret;
+ for (int i = all_current_commands.size () - 1; i >= 0; --i) {
+ RCommand *ret = all_current_commands[i];
+ if (ret->id () == id) {
+ RCommandStack::pop (ret);
+ all_current_commands.removeAt (i);
+ return ret;
+ }
+ }
+ RK_ASSERT (false);
+ return 0;
}
void RInterface::tryNextCommand () {
RK_TRACE (RBACKEND);
- if (!currentCommandRequest ()) return;
+ RCommand *command = RCommandStack::currentCommand ();
+ if (command_requests.isEmpty ()) {
+ // if the backend is not requesting anything, only priority commands will be pushed
+ if (!command) return;
+ if (!(command->type () & RCommand::PriorityCommand)) return;
+ if (all_current_commands.contains (command)) return;
+ }
+ bool priority = command && (command->type () & RCommand::PriorityCommand);
bool on_top_level = all_current_commands.isEmpty ();
- if (!(on_top_level && locked)) { // do not respect locks for sub-commands
- RCommand *command = RCommandStack::currentCommand ();
+ if (!(on_top_level && locked && !(priority))) { // do not respect locks for sub-commands
if (!on_top_level && all_current_commands.contains (command)) { // all sub-commands of the current command have finished
doNextCommand (0);
return;
@@ -164,7 +177,7 @@
command->status |= RCommand::Failed;
// notify ourselves...
- RCommand* dummy = popPreviousCommand ();
+ RCommand* dummy = popPreviousCommand (command->id ());
RK_ASSERT (dummy == command);
handleCommandOut (command);
return;
@@ -223,8 +236,17 @@
void RInterface::doNextCommand (RCommand *command) {
RK_TRACE (RBACKEND);
RBackendRequest* command_request = currentCommandRequest ();
- RK_ASSERT (command_request);
+ if (!command_request) {
+ if (!(command && (command->type () & RCommand::PriorityCommand))) return;
+ }
+ // importantly, this point is not reached for the fake startup command
+ if (RK_Debug_CommandStep) {
+ QTime t;
+ t.start ();
+ while (t.elapsed () < RK_Debug_CommandStep) {}
+ }
+
flushOutput (true);
RCommandProxy *proxy = 0;
if (command) {
@@ -248,9 +270,14 @@
}
}
- command_request->command = proxy;
- RKRBackendProtocolFrontend::setRequestCompleted (command_request);
- command_requests.pop_back ();
+ if (command && (command->type () & RCommand::PriorityCommand)) {
+ RKRBackendProtocolFrontend::sendPriorityCommand (proxy);
+ } else {
+ RK_ASSERT (command_request);
+ command_request->command = proxy;
+ RKRBackendProtocolFrontend::setRequestCompleted (command_request);
+ command_requests.pop_back ();
+ }
}
void RInterface::rCommandDone (RCommand *command) {
@@ -321,11 +348,10 @@
if (request->type == RBackendRequest::CommandOut) {
RCommandProxy *cproxy = request->takeCommand ();
RCommand *command = 0;
-#warning: when there are priority commands, the command to pop is NOT necessarily the one we last submitted!
// NOTE: the order of processing is: first try to submit the next command, then handle the old command.
// The reason for doing it this way, instead of the reverse, is that this allows the backend thread / process to continue working, concurrently
// NOTE: cproxy should only ever be 0 in the very first cycle
- if (cproxy) command = popPreviousCommand ();
+ if (cproxy) command = popPreviousCommand (cproxy->id);
command_requests.append (request);
tryNextCommand ();
if (cproxy) {
Modified: trunk/rkward/rkward/rbackend/rinterface.h
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.h 2013-04-21 13:10:07 UTC (rev 4706)
+++ trunk/rkward/rkward/rbackend/rinterface.h 2013-04-21 18:26:22 UTC (rev 4707)
@@ -101,7 +101,7 @@
RBackendRequest* currentCommandRequest () const { return (command_requests.isEmpty () ? 0 : command_requests.last ()); };
void tryNextCommand ();
void doNextCommand (RCommand *command);
- RCommand *popPreviousCommand ();
+ RCommand *popPreviousCommand (int id);
void handleCommandOut (RCommand *command);
bool previously_idle;
Modified: trunk/rkward/rkward/rbackend/rkrbackendprotocol_frontend.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackendprotocol_frontend.cpp 2013-04-21 13:10:07 UTC (rev 4706)
+++ trunk/rkward/rkward/rbackend/rkrbackendprotocol_frontend.cpp 2013-04-21 18:26:22 UTC (rev 4707)
@@ -75,6 +75,15 @@
qApp->postEvent (RKFrontendTransmitter::instance (), new RKRBackendEvent (req));
}
+void RKRBackendProtocolFrontend::sendPriorityCommand (RCommandProxy* proxy) {
+ RK_TRACE (RBACKEND);
+
+ RBackendRequest *req = new RBackendRequest (false, RBackendRequest::PriorityCommand);
+ req->command = proxy;
+ qApp->postEvent (RKFrontendTransmitter::instance (), new RKRBackendEvent (req));
+
+}
+
void RKRBackendProtocolFrontend::terminateBackend () {
RK_TRACE (RBACKEND);
Modified: trunk/rkward/rkward/rbackend/rkrbackendprotocol_frontend.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackendprotocol_frontend.h 2013-04-21 13:10:07 UTC (rev 4706)
+++ trunk/rkward/rkward/rbackend/rkrbackendprotocol_frontend.h 2013-04-21 18:26:22 UTC (rev 4707)
@@ -2,7 +2,7 @@
rkrbackendprotocol - description
-------------------
begin : Thu Nov 04 2010
- copyright : (C) 2010, 2011 by Thomas Friedrichsmeier
+ copyright : (C) 2010, 2011, 2013 by Thomas Friedrichsmeier
email : tfry at users.sourceforge.net
***************************************************************************/
@@ -24,6 +24,7 @@
class RInterface;
class QThread;
+class RCommandProxy;
class RKRBackendProtocolFrontend : public QObject {
public:
@@ -32,7 +33,8 @@
static void setRequestCompleted (RBackendRequest *request);
ROutputList flushOutput (bool force);
- void interruptCommand (int command_id);
+ static void interruptCommand (int command_id);
+ static void sendPriorityCommand (RCommandProxy *proxy);
void terminateBackend ();
void setupBackend ();
static RKRBackendProtocolFrontend* instance () { return _instance; };
Modified: trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h 2013-04-21 13:10:07 UTC (rev 4706)
+++ trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h 2013-04-21 18:26:22 UTC (rev 4707)
@@ -43,7 +43,8 @@
Debugger,
CommandLineIn, /**< The next line of the current user command has been submitted in the backend. */
Output, /**< A piece of output. Note: If the backend runs in a single process, output is handled in a pull fashion, instead of using requests. */
- Interrupt, /**< Interrupt evaluation. This request type originates in the frontend, not the backend (the only one so far). */
+ Interrupt, /**< Interrupt evaluation. This request type originates in the frontend, not the backend. */
+ PriorityCommand, /**< Send a command to be run during R's event processing. This request type originates in the frontend, not the backend. */
OutputStartedNotification, /**< Only used in the frontend: Notification that a new bit of output has arrived. Used to trigger flushing after a timeout. */
OtherRequest /**< Any other type of request. Note: which requests are in the enum, and which are not has mostly historical reasons. @see params */
};
More information about the rkward-tracker
mailing list