[rkward-cvs] SF.net SVN: rkward:[3662] trunk/rkward/rkward/rbackend

tfry at users.sourceforge.net tfry at users.sourceforge.net
Thu Jun 2 21:36:16 UTC 2011


Revision: 3662
          http://rkward.svn.sourceforge.net/rkward/?rev=3662&view=rev
Author:   tfry
Date:     2011-06-02 21:36:15 +0000 (Thu, 02 Jun 2011)

Log Message:
-----------
Fix deadlock issues in stdout-handling, and further cleanups

Modified Paths:
--------------
    trunk/rkward/rkward/rbackend/rkbackendtransmitter.cpp
    trunk/rkward/rkward/rbackend/rkfrontendtransmitter.cpp
    trunk/rkward/rkward/rbackend/rkfrontendtransmitter.h
    trunk/rkward/rkward/rbackend/rkrbackend.cpp
    trunk/rkward/rkward/rbackend/rkrbackend.h
    trunk/rkward/rkward/rbackend/rkrbackendprotocol_backend.cpp

Modified: trunk/rkward/rkward/rbackend/rkbackendtransmitter.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkbackendtransmitter.cpp	2011-06-02 18:19:29 UTC (rev 3661)
+++ trunk/rkward/rkward/rbackend/rkbackendtransmitter.cpp	2011-06-02 21:36:15 UTC (rev 3662)
@@ -63,6 +63,7 @@
 	connection->write ("\n");
 	connection->write (RKWARD_VERSION);
 	connection->write ("\n");
+	connection->waitForBytesWritten ();
 
 	QTimer* flush_timer = new QTimer (this);
 	connect (flush_timer, SIGNAL (timeout()), this, SLOT (flushOutput()));
@@ -115,7 +116,7 @@
 void RKRBackendTransmitter::flushOutput (bool force) {
 	if (!current_sync_requests.isEmpty ()) return;
 
-	if (!RKRBackend::this_pointer->fetchStdoutStderr (force, false)) return;
+	RKRBackend::this_pointer->fetchStdoutStderr (force);
 	ROutputList out = RKRBackend::this_pointer->flushOutput (force);
 	if (out.isEmpty ()) return;
 

Modified: trunk/rkward/rkward/rbackend/rkfrontendtransmitter.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkfrontendtransmitter.cpp	2011-06-02 18:19:29 UTC (rev 3661)
+++ trunk/rkward/rkward/rbackend/rkfrontendtransmitter.cpp	2011-06-02 21:36:15 UTC (rev 3662)
@@ -61,7 +61,6 @@
 	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 (finished (int, QProcess::ExitStatus)), this, SLOT (backendExit (int)));
 	QString backend_executable = KStandardDirs::findExe (QDir::toNativeSeparators (QCoreApplication::applicationDirPath () + "/rkward.rbackend"));
 	if (backend_executable.isEmpty ()) backend_executable = KStandardDirs::findExe (QDir::toNativeSeparators (QCoreApplication::applicationDirPath () + "/rbackend/rkward.rbackend"));	// for running directly from the build-dir
@@ -70,15 +69,10 @@
 
 	// fetch security token
 	if (!backend->canReadLine ()) backend->waitForReadyRead ();
-	token = QString::fromLocal8Bit (backend->readLine ());
-	token.chop (1);
-#ifdef Q_WS_WIN
-	token.chop (1);	// '\r', I suppose...
-#endif
+	token = QString::fromLocal8Bit (backend->readLine ()).trimmed ();
+	backend->closeReadChannel (QProcess::StandardError);
+	backend->closeReadChannel (QProcess::StandardOutput);
 
-	connect (backend, SIGNAL (readyReadStandardOutput ()), this, SLOT (newProcessOutput ()));
-	if (backend->bytesAvailable ()) newProcessOutput ();
-
 	exec ();
 
 	if (!connection) {
@@ -110,13 +104,6 @@
 	setConnection (con);
 }
 
-void RKFrontendTransmitter::newProcessOutput () {
-	RK_TRACE (RBACKEND);
-
-	QString output = QString::fromLocal8Bit (backend->readAll ());
-	handleOutput (output, output.size (), ROutput::Warning);
-}
-
 void RKFrontendTransmitter::requestReceived (RBackendRequest* request) {
 	RK_TRACE (RBACKEND);
 

Modified: trunk/rkward/rkward/rbackend/rkfrontendtransmitter.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkfrontendtransmitter.h	2011-06-02 18:19:29 UTC (rev 3661)
+++ trunk/rkward/rkward/rbackend/rkfrontendtransmitter.h	2011-06-02 21:36:15 UTC (rev 3662)
@@ -39,7 +39,6 @@
 	void requestReceived (RBackendRequest *request);
 private slots:
 	void connectAndEnterLoop ();
-	void newProcessOutput ();
 	void backendExit (int exitcode);
 private:
 	void handleTransmissionError (const QString &message);

Modified: trunk/rkward/rkward/rbackend/rkrbackend.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackend.cpp	2011-06-02 18:19:29 UTC (rev 3661)
+++ trunk/rkward/rkward/rbackend/rkrbackend.cpp	2011-06-02 21:36:15 UTC (rev 3662)
@@ -383,7 +383,7 @@
 }
 #endif
 
-bool RKRBackend::fetchStdoutStderr (bool forcibly, bool allow_blocking) {
+bool RKRBackend::fetchStdoutStderr (bool forcibly) {
 #ifndef Q_OS_WIN
 	if (!forcibly) {
 		if (!stdout_stderr_mutex.tryLock ()) return false;
@@ -391,14 +391,15 @@
 		stdout_stderr_mutex.lock ();
 	}
 
+	// it seems, setting this only once is not always enough.
+	fcntl (stdout_stderr_fd, F_SETFL, fcntl (stdout_stderr_fd, F_GETFL, 0) | O_NONBLOCK);
 	char buffer[1024];
 	while (true) {
 		int bytes = read (stdout_stderr_fd, buffer, 1023);
-		if (bytes < 0) break;
-		if (bytes != 0) {
-			buffer[bytes] = '\0';
-			handleOutput (current_locale_codec->toUnicode (buffer, bytes), bytes, ROutput::Warning, allow_blocking);
-		}
+		if (bytes <= 0) break;
+		buffer[bytes] = '\0';
+		// NOTE: we must not risk blocking inside handleOutput, while the stdout_stderr_mutex is locked!
+		handleOutput (current_locale_codec->toUnicode (buffer, bytes), bytes, ROutput::Warning, false);
 	}
 
 	stdout_stderr_mutex.unlock ();
@@ -425,7 +426,7 @@
 		}
 	}
 
-	RKRBackend::this_pointer->fetchStdoutStderr (true, true);
+	RKRBackend::this_pointer->fetchStdoutStderr (true);
 	RKRBackend::this_pointer->handleOutput (RKRBackend::this_pointer->current_locale_codec->toUnicode (buf, buflen), buflen, type == 0 ? ROutput::Output : ROutput::Warning);
 }
 
@@ -960,13 +961,10 @@
 #ifndef Q_OS_WIN
 	// re-direct stdout / stderr to a pipe, so we can read output from system() calls
 	int pfd[2];
-	pipe(pfd);
-	for (int n=0; n<2; n++) {
-		fcntl (pfd[n], F_SETFL, fcntl (pfd[n], F_GETFL, 0) | O_NONBLOCK);
-	}
-	dup2(STDOUT_FILENO, STDERR_FILENO);		// single channel to avoid interleaving hell, for now.
-	dup2(pfd[1], STDOUT_FILENO);
-	close(pfd[1]);
+	pipe (pfd);
+	dup2 (STDOUT_FILENO, STDERR_FILENO);		// single channel to avoid interleaving hell, for now.
+	dup2 (pfd[1], STDOUT_FILENO);
+	close (pfd[1]);
 	stdout_stderr_fd = pfd[0];
 #endif
 

Modified: trunk/rkward/rkward/rbackend/rkrbackend.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackend.h	2011-06-02 18:19:29 UTC (rev 3661)
+++ trunk/rkward/rkward/rbackend/rkrbackend.h	2011-06-02 21:36:15 UTC (rev 3662)
@@ -187,7 +187,7 @@
 /** check stdout and stderr for new output (from sub-processes). Since this function is called from both threads, it is protected by a mutex.
  *  @param forcibly: if false, and the other thread currently has a lock on the mutex, do nothing, and return false.
  *  @returns: true, if output was actually fetched (or no output was available), false, if the function gave up on a locked mutex. */
-	bool fetchStdoutStderr (bool forcibly, bool allow_blocking);
+	bool fetchStdoutStderr (bool forcibly);
 private:
 	void clearPendingInterrupt ();
 protected:

Modified: trunk/rkward/rkward/rbackend/rkrbackendprotocol_backend.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackendprotocol_backend.cpp	2011-06-02 18:19:29 UTC (rev 3661)
+++ trunk/rkward/rkward/rbackend/rkrbackendprotocol_backend.cpp	2011-06-02 21:36:15 UTC (rev 3662)
@@ -32,6 +32,7 @@
 #	include "kcomponentdata.h"
 #	include "kglobal.h"
 #	include "rktransmitter.h"
+#	include <stdio.h>
 #endif
 
 #ifdef RKWARD_THREADED
@@ -104,6 +105,9 @@
 		KComponentData data ("rkward");
 		KGlobal::locale ();		// to initialize it in the primary thread
 
+		setvbuf (stdout, NULL, _IONBF, 0);
+		setvbuf (stderr, NULL, _IONBF, 0);
+
 		RK_Debug_File = new KTemporaryFile ();
 		RK_Debug_File->setPrefix ("rkward.rbackend");
 		RK_Debug_File->setAutoRemove (false);


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