[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