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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Wed Nov 17 19:14:00 UTC 2010


Revision: 3192
          http://rkward.svn.sourceforge.net/rkward/?rev=3192&view=rev
Author:   tfry
Date:     2010-11-17 19:14:00 +0000 (Wed, 17 Nov 2010)

Log Message:
-----------
Separate process backend is basically functional (but a lot of small stuff is still left to do).
Performance looks better than expected.
Hooray.

Modified Paths:
--------------
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackend.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rkward.cpp

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-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp	2010-11-17 19:14:00 UTC (rev 3192)
@@ -131,6 +131,7 @@
 	RK_ASSERT (previous_command == 0);
 	RK_ASSERT (!all_current_commands.isEmpty ());
 	previous_command = all_current_commands.takeLast ();
+qDebug ("previous command: %d", previous_command->id ());
 	RCommandStack::currentStack ()->pop ();
 }
 
@@ -328,7 +329,6 @@
 		issueCommand ("rk.set.output.html.file (\"" + RKSettingsModuleGeneral::filesPath () + "/rk_out.html\")\n", RCommand::App | RCommand::Sync, QString (), this, SET_RUNTIME_OPTS, chain);
 
 		closeChain (chain);
-		RKRBackendProtocolFrontend::setRequestCompleted (request);
 	} else {
 		processRBackendRequest (request);
 	}
@@ -694,6 +694,8 @@
 		message += i18n ("\nIt will be shut down immediately. This means, you can not use any more functions that rely on the R backend. I.e. you can do hardly anything at all, not even save the workspace (but if you're lucky, R already did that). What you can do, however, is save any open command-files, the output, or copy data out of open data editors. Quit RKWard after that.\nSince this should never happen, please write a mail to rkward-devel at lists.sourceforge.net, and tell us, what you were trying to do, when this happened. Sorry!");
 		KMessageBox::error (0, message, i18n ("R engine has died"));
 		backend_dead = true;
+	} else {
+		RK_ASSERT (false);
 	}
 
 	RKRBackendProtocolFrontend::setRequestCompleted (request);

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.cpp	2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.cpp	2010-11-17 19:14:00 UTC (rev 3192)
@@ -18,6 +18,8 @@
 #include "rkfrontendtransmitter.h"
 
 #include "rkrbackendprotocol_frontend.h"
+#include "../misc/rkcommonfunctions.h"
+#include "../settings/rksettingsmodulegeneral.h"
 
 #include "kstandarddirs.h"
 #include <QCoreApplication>
@@ -28,56 +30,62 @@
 RKFrontendTransmitter::RKFrontendTransmitter () : QThread () {
 	RK_TRACE (RBACKEND);
 
-	// start server
 	connection = 0;
-	if (!server.listen ("rkward")) handleTransmitError ("failure to start frontend server: " + server.errorString ());
-	connect (&server, SIGNAL (newConnection ()), this, SLOT (connectAndEnterLoop ()));
 
-	// start backend
-	QStringList args;
-	args.append ("--debug-level " + QString::number (RK_Debug_Level));
-	args.append ("--server-name " + server.fullServerName ());
-	backend.setProcessChannelMode (QProcess::MergedChannels);	// at least for now. Seems difficult to get interleaving right, without this.
-	connect (&backend, SIGNAL (readyReadStandardOutput ()), this, SLOT (newProcessOutput ()));
-	connect (&backend, SIGNAL (finished (int, QProcess::ExitStatus)), this, SLOT (backendExit (int, QProcess::ExitStatus)));
-	backend.start (KStandardDirs::findExe ("rkward.rbackend", QCoreApplication::applicationDirPath ()), args, QIODevice::ReadOnly);
-
 	RK_ASSERT (_instance == 0);
 	_instance = this;
+
+	moveToThread (this);
+	start ();
 }
 
 RKFrontendTransmitter::~RKFrontendTransmitter () {
 	RK_TRACE (RBACKEND);
 
-	RK_ASSERT (!server.isListening ());
+	RK_ASSERT (!server->isListening ());
 	delete connection;
 }
 
 void RKFrontendTransmitter::run () {
-	RK_ASSERT (connection);
+	RK_TRACE (RBACKEND);
 
-	connection->moveToThread (this);
-	connect (connection, SIGNAL (stateChanged (QLocalSocket::LocalSocketState)), this, SLOT (connectionStateChanged (QLocalSocket::LocalSocketState)));
-	connect (connection, SIGNAL (readyRead ()), this, SLOT (newConnectionData ()));
-	backend.moveToThread (this);
+	// start server
+	server = new QLocalServer (this);
+	if (!server->listen ("rkward")) handleTransmitError ("failure to start frontend server: " + server->errorString ());
+	connect (server, SIGNAL (newConnection ()), this, SLOT (connectAndEnterLoop ()), Qt::QueuedConnection);
 
+	// start backend
+	backend = new QProcess (this);
+	QStringList args;
+	args.append ("--debug-level " + QString::number (RK_Debug_Level));
+	args.append ("--server-name " + server->fullServerName ());
+	args.append ("--data-dir " + RKSettingsModuleGeneral::filesPath ());
+	backend->setProcessChannelMode (QProcess::MergedChannels);	// at least for now. Seems difficult to get interleaving right, without this.
+	connect (backend, SIGNAL (readyReadStandardOutput ()), this, SLOT (newProcessOutput ()));
+	connect (backend, SIGNAL (finished (int, QProcess::ExitStatus)), this, SLOT (backendExit (int, QProcess::ExitStatus)));
+	QString backend_executable = KStandardDirs::findExe ("rkward.rbackend", QCoreApplication::applicationDirPath () + "/rbackend");
+	if (backend_executable.isEmpty ()) backend_executable = KStandardDirs::findExe ("rkward.rbackend", QCoreApplication::applicationDirPath ());
+	RK_ASSERT (!backend_executable.isEmpty ());
+	backend->start (backend_executable, args, QIODevice::ReadOnly);
+
 	exec ();
 }
 
 void RKFrontendTransmitter::connectAndEnterLoop () {
 	RK_TRACE (RBACKEND);
-	RK_ASSERT (server.hasPendingConnections ());
+	RK_ASSERT (server->hasPendingConnections ());
 
-	connection = server.nextPendingConnection ();
-	server.close ();
+	connection = server->nextPendingConnection ();
+	server->close ();
 
-	start ();
+	connect (connection, SIGNAL (stateChanged (QLocalSocket::LocalSocketState)), this, SLOT (connectionStateChanged ()));
+	connect (connection, SIGNAL (readyRead ()), this, SLOT (newConnectionData ()));
 }
 
 void RKFrontendTransmitter::newProcessOutput () {
 	RK_TRACE (RBACKEND);
 #warning TODO: fix interleaving
-	QString output = QString::fromLocal8Bit (backend.readAll ());
+	QString output = QString::fromLocal8Bit (backend->readAll ());
 	handleOutput (output, output.size (), ROutput::Warning);
 }
 
@@ -105,8 +113,20 @@
 	}
 
 	RBackendRequest *req = RKRBackendSerializer::unserialize (receive_buffer);
+	if (req->type == RBackendRequest::Output) {
+		ROutputList* list = req->output;
+		for (int i = 0; i < list->size (); ++i) {
+			ROutput *out = (*list)[i];
+			handleOutput (out->output, out->output.length (), out->type);
+			delete (out);
+		}
+		req->output = 0;
+		RK_ASSERT (req->synchronous);
+		writeRequest (req);	// to tell the backend, that we are keeping up. This also deletes the request.
+		return;
+	}
 	RKRBackendEvent* event = new RKRBackendEvent (req);
-	qApp->postEvent (RKRBackendProtocolFrontend::instance ()->parent (), event);
+	qApp->postEvent (RKRBackendProtocolFrontend::instance (), event);
 }
 
 void RKFrontendTransmitter::backendExit (int exitcode, QProcess::ExitStatus exitstatus) {
@@ -114,16 +134,16 @@
 
 	RBackendRequest* req = new RBackendRequest (false, RBackendRequest::BackendExit);
 	RKRBackendEvent* event = new RKRBackendEvent (req);
-	qApp->postEvent (RKRBackendProtocolFrontend::instance ()->parent (), event);
+	qApp->postEvent (RKRBackendProtocolFrontend::instance (), event);
 }
 
-void RKFrontendTransmitter::connectionStateChanged (QLocalSocket::LocalSocketState state) {
-	if (state != QLocalSocket::UnconnectedState) return;		// only interested in connection failure
+void RKFrontendTransmitter::connectionStateChanged () {
+	if (connection->state () != QLocalSocket::UnconnectedState) return;		// only interested in connection failure
 	RK_TRACE (RBACKEND);
 
 	RBackendRequest* req = new RBackendRequest (false, RBackendRequest::BackendExit);
 	RKRBackendEvent* event = new RKRBackendEvent (req);
-	qApp->postEvent (RKRBackendProtocolFrontend::instance ()->parent (), event);
+	qApp->postEvent (RKRBackendProtocolFrontend::instance (), event);
 }
 
 void RKFrontendTransmitter::writeRequest (RBackendRequest *request) {
@@ -132,6 +152,7 @@
 	QByteArray buffer = RKRBackendSerializer::serialize (*request);
 	connection->write (QString::number (buffer.length ()).toLocal8Bit () + "\n");
 	connection->write (buffer);
+	connection->flush ();
 	delete request;
 }
 

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.h	2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.h	2010-11-17 19:14:00 UTC (rev 3192)
@@ -50,13 +50,13 @@
 	void newProcessOutput ();
 	void newConnectionData ();
 	void backendExit (int exitcode, QProcess::ExitStatus exitstatus);
-	void connectionStateChanged (QLocalSocket::LocalSocketState state);
+	void connectionStateChanged ();
 private:
 	void handleTransmitError (const QString &message);
 
 	int current_request_length;
-	QProcess backend;
-	QLocalServer server;
+	QProcess* backend;
+	QLocalServer* server;
 	QLocalSocket* connection;
 	static RKFrontendTransmitter *_instance;
 };

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackend.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackend.cpp	2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackend.cpp	2010-11-17 19:14:00 UTC (rev 3192)
@@ -25,6 +25,7 @@
 #include <qstring.h>
 #include <QStringList>
 #include <QThread>
+#include <QDir>
 #include <qtextcodec.h>
 #include <klocale.h>
 
@@ -368,7 +369,16 @@
 	RKRBackend::this_pointer->r_running = false;	// To signify we have finished everything else and are now trying to create an emergency save (if applicable)
 
 	if (RKRBackend::this_pointer->killed == RKRBackend::EmergencySaveThenExit) {
-		if (R_DirtyImage) R_SaveGlobalEnvToFile (RKCommonFunctions::getUseableRKWardSavefileName ("rkward_recover", ".RData").toLocal8Bit ());
+		QString filename;
+		QDir dir (RKRBackendProtocolBackend::dataDir ());
+		int i=0;
+		while (true) {
+			filename = "rkward_recover" + QString::number (i) + ".RData";
+			if (!dir.exists (filename)) break;
+			i++;
+		}
+
+		if (R_DirtyImage) R_SaveGlobalEnvToFile (filename.toLocal8Bit ());
 	}
 
 	RKRBackend::this_pointer->killed = RKRBackend::AlreadyDead;	// just in case

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.cpp	2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.cpp	2010-11-17 19:14:00 UTC (rev 3192)
@@ -88,8 +88,10 @@
 			RK_TRACE (RBACKEND);
 			RK_ASSERT (_instance == 0);
 			_instance = this;
+			connection = 0;
 
-			connection.connectToServer (servername);	// acutal connection will be done inside run()
+			moveToThread (this);
+			RKRBackendTransmitter::servername = servername;
 		};
 
 		~RKRBackendTransmitter () {
@@ -104,7 +106,10 @@
 		void run () {
 			RK_TRACE (RBACKEND);
 
-			if (!connection.waitForConnected ()) handleTransmitError ("Could not connect: %s");
+			connection = new QLocalSocket (this);
+			connection->connectToServer (servername);	// acutal connection will be done inside run()
+
+			if (!connection->waitForConnected ()) handleTransmitError ("Could not connect: %s");
 #warning do handshake
 			while (1) {
 				flushOutput (false);
@@ -137,10 +142,10 @@
 
 			// send request
 			QByteArray buffer = RKRBackendSerializer::serialize (*request);
-			connection.write (QString::number (buffer.length ()).toLocal8Bit () + "\n");
-			connection.write (buffer);
-			while (connection.bytesToWrite ()) {
-				if (!connection.waitForBytesWritten ()) handleTransmitError ("Could not connect: %s");
+			connection->write (QString::number (buffer.length ()).toLocal8Bit () + "\n");
+			connection->write (buffer);
+			while (connection->bytesToWrite ()) {
+				if (!connection->waitForBytesWritten ()) handleTransmitError ("Could not connect: %s");
 #warning, at this point we could check for an early reply to CommandOut requests
 // currently, there is not as much concurrency between the processes as there could be. This is due to the fact, that the transmitter will always block until the result of the
 // last command has been serialized and transmitted to the frontend. Instead, it could check for and fetch the next command, already (if available), to keep the backend going.
@@ -154,7 +159,6 @@
 			// NOTE: currently, in the backend, we *never* expect a read without a synchronous request
 			RBackendRequest* reply = RKRBackendSerializer::unserialize (fetchTransmission (true));
 			request->mergeReply (reply);
-			RK_ASSERT (reply->done);
 			delete reply;
 #warning Read up on whether volatile provides a good enough memory barrier at this point!
 			request->done = true;	// must be the very last thing we do with the request!
@@ -164,32 +168,34 @@
 		@param block Block until a transmission was received.
 		@note @em If a transmission is available, this will always block until the transmission has been received in full. */
 		QByteArray fetchTransmission (bool block) {
+			RK_ASSERT (connection);
+
 			QByteArray receive_buffer;
 			int expected_length = 0;
 			bool got_header = false;
-			bool have_data = false;
 			while (1) {
-				have_data = have_data || connection.waitForReadyRead (1);
-				if (!connection.isOpen ()) {
+				connection->waitForReadyRead (1);
+				if (!connection->isOpen ()) {
 					handleTransmitError ("Connection closed unexepctedly. Last error: %s");
 					return receive_buffer;
 				}
-				if (!have_data) {
+				if (!connection->bytesAvailable ()) {
 					if (!block) return receive_buffer;
 					continue;
 				}
+
 				RK_TRACE (RBACKEND);
 				if (!got_header) {
-					if (!connection.canReadLine ()) continue;	// at this point we have received *something*, but not even a full header, yet.
+					if (!connection->canReadLine ()) continue;	// at this point we have received *something*, but not even a full header, yet.
 
-					QString line = QString::fromLocal8Bit (connection.readLine ());
+					QString line = QString::fromLocal8Bit (connection->readLine ());
 					bool ok;
 					expected_length = line.toInt (&ok);
 					if (!ok) handleTransmitError ("Protocol header error. Last connection error was: %s");
 					got_header = true;
 				}
 
-				receive_buffer.append (connection.read (expected_length - receive_buffer.length ()));
+				receive_buffer.append (connection->read (expected_length - receive_buffer.length ()));
 				if (receive_buffer.length () >= expected_length) return receive_buffer;
 			}
 		}
@@ -205,14 +211,15 @@
 		}
 
 		void handleTransmitError (const char* message_template) {
-			printf (message_template, qPrintable (connection.errorString ()));
+			printf (message_template, qPrintable (connection->errorString ()));
 		}
 
-		QLocalSocket connection;
+		QLocalSocket* connection;
 		QList<RBackendRequest *> current_requests;		// there *can* be multiple active requests (if the first ones are asynchronous)
 		QMutex request_mutex;
 		static RKRBackendTransmitter* _instance;
 		static RKRBackendTransmitter* instance () { return _instance; };
+		QString servername;
 	};
 	RKRBackendTransmitter* RKRBackendTransmitter::_instance = 0;
 
@@ -237,12 +244,16 @@
 		KGlobal::locale ();		// to initialize it in the primary thread
 
 		QString servername;
+		QString data_dir;
 		QStringList args = app.arguments ();
 		for (int i = 1; i < args.count (); ++i) {
 			if (args[i].startsWith ("--debug-level")) {
-				RK_Debug_Level = args.value (++i, QString ()).toInt ();
+				RK_Debug_Level = args[i].section (' ', 1).toInt ();
 			} else if (args[i].startsWith ("--server-name")) {
-				servername = args.value (++i, QString ());
+				servername = args[i].section (' ', 1);
+			} else if (args[i].startsWith ("--data-dir")) {
+#warning What about paths with spaces?!
+				data_dir = args[i].section (' ', 1);
 			} else {
 				printf ("unkown argument %s", qPrintable (args[i]));
 			}
@@ -252,14 +263,14 @@
 		}
 
 		RKRBackendTransmitter transmitter (servername);
-		RKRBackendProtocolBackend backend ();
+		RKRBackendProtocolBackend backend (data_dir);
 		transmitter.start ();
 		RKRBackend::this_pointer->run ();
 	}
 #endif
 
 RKRBackendProtocolBackend* RKRBackendProtocolBackend::_instance = 0;
-RKRBackendProtocolBackend::RKRBackendProtocolBackend () {
+RKRBackendProtocolBackend::RKRBackendProtocolBackend (const QString &storage_dir) {
 	RK_TRACE (RBACKEND);
 
 	_instance = this;
@@ -272,6 +283,7 @@
 	r_thread = QThread::currentThread ();	// R thread == main thread
 	r_thread_id = QThread::currentThreadId ();
 #endif
+	data_dir = storage_dir;
 }
 
 RKRBackendProtocolBackend::~RKRBackendProtocolBackend () {

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.h	2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.h	2010-11-17 19:14:00 UTC (rev 3192)
@@ -25,17 +25,19 @@
 class RKRBackendProtocolBackend {
 public:
 	static bool inRThread ();
+	static QString dataDir () { return _instance->data_dir; };
+
+	RKRBackendProtocolBackend (const QString &data_dir);
+	~RKRBackendProtocolBackend ();
 protected:
 friend class RKRBackendProtocolFrontend;
 friend class RKRBackend;
 friend class RKRBackendThread;
-	RKRBackendProtocolBackend ();
-	~RKRBackendProtocolBackend ();
-
 	void sendRequest (RBackendRequest *request);
 	static void msleep (int delay);
 	static void interruptProcessing ();
 	static RKRBackendProtocolBackend* instance () { return _instance; };
+	QString data_dir;
 private:
 	static RKRBackendProtocolBackend* _instance;
 	QThread *r_thread;

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.cpp	2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.cpp	2010-11-17 19:14:00 UTC (rev 3192)
@@ -79,8 +79,6 @@
 }
 
 ROutputList RKRBackendProtocolFrontend::flushOutput (bool force) {
-	RK_TRACE (RBACKEND);
-
 #ifdef RKWARD_THREADED
 	return (RKRBackend::this_pointer->flushOutput (force));
 #else
@@ -96,7 +94,7 @@
 	RKRBackendProtocolBackend::interruptProcessing ();
 #else
 //	kill (SIGUSR1, pid_of_it);
-#warning wont't work on windows!
+#warning will not work on windows!
 #endif
 }
 
@@ -107,11 +105,10 @@
 	RKRBackend::this_pointer->kill ();
 #else
 //	kill (SIGUSR2, pid_of_it);
-#warning wont't work on windows!
+#warning will not work on windows!
 #endif
 }
 
-#ifdef RKWARD_THREADED
 void RKRBackendProtocolFrontend::customEvent (QEvent *e) {
 	if (((int) e->type ()) == ((int) RKRBackendEvent::RKWardEvent)) {
 		RKRBackendEvent *ev = static_cast<RKRBackendEvent*> (e);
@@ -121,5 +118,4 @@
 		return;
 	}
 }
-#endif
 

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.h	2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.h	2010-11-17 19:14:00 UTC (rev 3192)
@@ -37,10 +37,9 @@
 	void setupBackend (QVariantMap backend_params);
 	static RKRBackendProtocolFrontend* instance () { return _instance; };
 protected:
-#ifdef RKWARD_THREADED
 /** needed to handle the QEvents, the R thread is sending (notifications on what's happening in the backend thread) */
 	void customEvent (QEvent *e);
-#else
+#ifndef RKWARD_THREADED
 	QThread* main_thread;
 #endif
 private:

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rkward.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rkward.cpp	2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rkward.cpp	2010-11-17 19:14:00 UTC (rev 3192)
@@ -156,14 +156,14 @@
 	RK_TRACE (APP);
 
 	// these would not be strictly necessary, as we're exiting the app, anyway.
-	delete RControlWindow::getControl ();
-	delete RKGlobals::rInterface ();
 	delete RObjectList::getObjectList ();
 	delete RObjectBrowser::mainBrowser ();
 	delete RKCommandLog::getLog ();
 	delete RKConsole::mainConsole ();
 	delete RKHelpSearchWindow::mainHelpSearch ();
 	delete RKGlobals::tracker ();
+	delete RKGlobals::rInterface ();
+	delete RControlWindow::getControl ();
 }
 
 void RKWardMainWindow::closeEvent (QCloseEvent *e) {


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