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

tfry at users.sf.net tfry at users.sf.net
Tue Apr 23 10:48:20 UTC 2013


Revision: 4713
          http://sourceforge.net/p/rkward/code/4713
Author:   tfry
Date:     2013-04-23 10:48:18 +0000 (Tue, 23 Apr 2013)
Log Message:
-----------
If possible, use input handlers woken by a pipe for event processing. This works much better on Unix (but on Windows, we have to fall back to R_PolledEvents).
Also, make sure not to try processing priority commands in a forked child or killed backend.

Modified Paths:
--------------
    trunk/rkward/rkward/rbackend/rkrbackend.cpp
    trunk/rkward/rkward/rbackend/rkrbackend.h
    trunk/rkward/rkward/rbackend/rkreventloop.cpp
    trunk/rkward/rkward/rbackend/rkreventloop.h
    trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
    trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp

Modified: trunk/rkward/rkward/rbackend/rkrbackend.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackend.cpp	2013-04-23 09:58:17 UTC (rev 4712)
+++ trunk/rkward/rkward/rbackend/rkrbackend.cpp	2013-04-23 10:48:18 UTC (rev 4713)
@@ -1038,7 +1038,7 @@
 
 	connectCallbacks();
 	RKInsertToplevelStatementFinishedCallback (0);
-	RKREventLoop::setEventHandler (doPendingPriorityCommands);
+	RKREventLoop::setRKEventHandler (doPendingPriorityCommands);
 	default_global_context = R_GlobalContext;
 
 	// get info on R runtime version
@@ -1290,11 +1290,13 @@
 	QMutexLocker lock (&priority_command_mutex);
 	RK_ASSERT (!(command && pending_priority_command));      // for the time being, we support only one priority command at a time
 	pending_priority_command = command;
+	RKREventLoop::wakeRKEventHandler ();
 }
 
 void doPendingPriorityCommands () {
 	RK_TRACE (RBACKEND);
 
+	if (RKRBackend::this_pointer->killed) return;
 	RCommandProxy *command = RKRBackend::this_pointer->pending_priority_command;
 	if (command) {
 		RK_DEBUG (RBACKEND, DL_DEBUG, "running priority command %s", qPrintable (command->command));

Modified: trunk/rkward/rkward/rbackend/rkrbackend.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackend.h	2013-04-23 09:58:17 UTC (rev 4712)
+++ trunk/rkward/rkward/rbackend/rkrbackend.h	2013-04-23 10:48:18 UTC (rev 4713)
@@ -105,8 +105,6 @@
 @param datatype the data type that should be (attempted to be) returned
 @returns a pointer to the RCommandProxy-instance that was created and used, internally. You can query this pointer for status and data. Be sure to delete it, when done. */
 	RCommandProxy *runDirectCommand (const QString &command, RCommand::CommandTypes datatype); 
-/** call this periodically to make R's x11 windows process their events */
-	static void processX11Events ();
 
 	void handleRequest (RBackendRequest *request) { handleRequest (request, true); };
 /** A relic of history. In contrast to handlePlainGenericRequest(), these requests support running sub-commands. However, the remaining requests which are currently handled this way

Modified: trunk/rkward/rkward/rbackend/rkreventloop.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkreventloop.cpp	2013-04-23 09:58:17 UTC (rev 4712)
+++ trunk/rkward/rkward/rbackend/rkreventloop.cpp	2013-04-23 10:48:18 UTC (rev 4713)
@@ -26,7 +26,7 @@
 
 extern "C" void RK_doIntr ();
 
-void processX11EventsWorker (void *) {
+static void processX11EventsWorker (void *) {
 // this basically copied from R's unix/sys-std.c (Rstd_ReadConsole)
 #ifndef Q_WS_WIN
 	for (;;) {
@@ -68,18 +68,62 @@
 	RKRBackend::RKRBackend::repl_status.eval_depth--;
 }
 
-void (* RK_old_R_PolledEvents)();
-void (* RK_eventHandlerFunction)() = 0;
+static void (* RK_old_R_PolledEvents)();
+static void (* RK_eventHandlerFunction)() = 0;
 
-void RK_eventHandlerChain () {
+#ifndef Q_OS_WIN
+// NOTE: input-handler-based event loop mechanism is heavily inspired by (but not quite the same as in) package qtbase version 1.0.4 by Michael Lawrence, Deepayan Sarkar.
+// URL: http://qtinterfaces.r-forge.r-project.org
+static int ifd = 0;
+static int ofd = 0;
+static char buf[16];
+static bool rk_event_handler_triggered = false;
+#	include <unistd.h>
+static void RK_eventHandlerWrapper (void *data) {
+	Q_UNUSED (data);
+	rk_event_handler_triggered = false;
+	char buf[16];
+	bool read_ok = read (ifd, buf, 16);
+	RK_ASSERT (read_ok);
+	RK_eventHandlerFunction ();
+}
+#endif
+
+static void RK_eventHandlerChain () {
 	if (RK_eventHandlerFunction) RK_eventHandlerFunction ();
 	if (RK_old_R_PolledEvents) RK_old_R_PolledEvents ();
 }
 
-void RKREventLoop::setEventHandler (void (* handler) ()) {
+void RKREventLoop::setRKEventHandler (void (* handler) ()) {
+	RK_TRACE (RBACKEND);
 	RK_ASSERT (!RK_eventHandlerFunction);
+	RK_eventHandlerFunction = handler;
 
+	bool ok = false;
+#ifndef Q_OS_WIN
+	int fds[2];
+
+	if (!pipe (fds)) {
+		ifd = fds[0];
+		ofd = fds[1];
+		addInputHandler (R_InputHandlers, ifd, RK_eventHandlerWrapper, 32);
+		ok = true;
+	}
+#endif
+	if (ok) return;
+
+	// if pipe method did not work, fall back to R_PolledEvents
 	RK_old_R_PolledEvents = R_PolledEvents;
-	RK_eventHandlerFunction = handler;
 	R_PolledEvents = RK_eventHandlerChain;
 }
+
+void RKREventLoop::wakeRKEventHandler () {
+#ifndef Q_OS_WIN
+	if (!ofd) return;
+	if (rk_event_handler_triggered) return;
+	rk_event_handler_triggered = true;
+	*buf = 0;
+	bool write_ok = write (ofd, buf, 1);
+	RK_ASSERT (write_ok);
+#endif
+}

Modified: trunk/rkward/rkward/rbackend/rkreventloop.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkreventloop.h	2013-04-23 09:58:17 UTC (rev 4712)
+++ trunk/rkward/rkward/rbackend/rkreventloop.h	2013-04-23 10:48:18 UTC (rev 4713)
@@ -19,8 +19,23 @@
 #define RKREVENTLOOP_H
 
 namespace RKREventLoop {
+/** This - somewhat misnamed - function takes care of processing R's events (not only X11).
+ *  It is like R_ProcessEvents (except for the scary warning in the header file, that R_ProcessEvents does not work on Unix),
+ *  but for safety, event processing is done inside a toplevel context. Thus, this function is guaranteed to return.
+ *  Call this periodically to make R's x11 windows process their events */
 	void processX11Events ();
-	void setEventHandler (void (* handler) ());
+/** Register a function that will be called inside R's event loop. Implementation differs across platforms. The handler function
+ * @em might get called unconditionally (hooked into R_PolledEvents()), periodically, or only when needed. To make sure, the
+ * latter works, call wakeRKEventHandler() whenever there is(are) some new task(s) for the handler.
+ * 
+ * Event on platforms where the event handler is called "on demand", there is no guarantee, that this happens exactly once per demand.
+ * The registered event handling function should be prepared to handle zero, one, or several new events.
+ * 
+ * Currently, only one handler may be registered. */
+	void setRKEventHandler (void (* handler) ());
+/** Call this (potentially from a separate thread) to wake the handler set by setRKEventHandler() in the next iteration of 
+ * R's event loop. */
+	void wakeRKEventHandler ();
 };
 
 #endif

Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp	2013-04-23 09:58:17 UTC (rev 4712)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp	2013-04-23 10:48:18 UTC (rev 4713)
@@ -114,7 +114,7 @@
 
 void RKGraphicsDevice::setAreaSize (const QSize& size) {
 	if (painter.isActive ()) painter.end ();
-	RK_DEBUG (GRAPHICS_DEVICE, DL_WARNING, "New Size %d, %d (view size is %d, %d)", size.width (), size.height (), view->width (), view->height ());
+	RK_DEBUG (GRAPHICS_DEVICE, DL_INFO, "New Size %d, %d (view size is %d, %d)", size.width (), size.height (), view->width (), view->height ());
 	area = QPixmap (size.width (), size.height ());
 	clear ();
 }

Modified: trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp	2013-04-23 09:58:17 UTC (rev 4712)
+++ trunk/rkward/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp	2013-04-23 10:48:18 UTC (rev 4713)
@@ -51,7 +51,6 @@
 				if (!connection->waitForBytesWritten (10)) {
 					checkHandleError ();
 				}
-#warning TODO: Use R_CheckUserInterrupt(), instead?
 				if (connection->bytesToWrite ()) RKREventLoop::processX11Events ();
 			}
 			while (!RKGraphicsDeviceBackendTransmitter::streamer.readInBuffer ()) {





More information about the rkward-tracker mailing list