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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Thu Oct 7 14:55:20 UTC 2010


Revision: 3112
          http://rkward.svn.sourceforge.net/rkward/?rev=3112&view=rev
Author:   tfry
Date:     2010-10-07 14:55:19 +0000 (Thu, 07 Oct 2010)

Log Message:
-----------
Try to pass SIGILL and SIGABRT to the proper handlers (in addtion to SIGSEGV). Attempt to save the workspace on crashes.

Modified Paths:
--------------
    trunk/rkward/ChangeLog
    trunk/rkward/rkward/misc/rkcommonfunctions.cpp
    trunk/rkward/rkward/misc/rkcommonfunctions.h
    trunk/rkward/rkward/rbackend/rembedinternal.cpp
    trunk/rkward/rkward/rbackend/rembedinternal.h
    trunk/rkward/rkward/rbackend/rinterface.cpp
    trunk/rkward/rkward/rbackend/rinterface.h
    trunk/rkward/rkward/rbackend/rksignalsupport.cpp
    trunk/rkward/rkward/rbackend/rksignalsupport.h

Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog	2010-10-07 10:31:16 UTC (rev 3111)
+++ trunk/rkward/ChangeLog	2010-10-07 14:55:19 UTC (rev 3112)
@@ -1,3 +1,5 @@
+- Attempt to save workspace on crashes		TODO: detect recovery-file at startup, and offer to load it.
+- Also try to relay SIGABRT and SIGILL to the proper signal handlers
 - Removed the remainder of the PHP scripting backend
 - Fixed: Would crash on tcl/tk events in some cases
 

Modified: trunk/rkward/rkward/misc/rkcommonfunctions.cpp
===================================================================
--- trunk/rkward/rkward/misc/rkcommonfunctions.cpp	2010-10-07 10:31:16 UTC (rev 3111)
+++ trunk/rkward/rkward/misc/rkcommonfunctions.cpp	2010-10-07 14:55:19 UTC (rev 3112)
@@ -2,7 +2,7 @@
                           rkcommonfunctions  -  description
                              -------------------
     begin                : Mon Oct 17 2005
-    copyright            : (C) 2005, 2006, 2007, 2009 by Thomas Friedrichsmeier
+    copyright            : (C) 2005, 2006, 2007, 2009, 2010 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -19,11 +19,14 @@
 #include <qstringlist.h>
 #include <qdom.h>
 #include <qregexp.h>
+#include <QDir>
 
 #include <kxmlguiclient.h>
 #include <kglobal.h>
 #include <kstandarddirs.h>
 
+#include "../settings/rksettingsmodulegeneral.h"
+
 namespace RKCommonFunctions {
 	void removeNamedElementsRecursive (const QStringList &names, QDomNode &parent) {
 		QDomNode nchild;
@@ -136,7 +139,19 @@
 		return (KGlobal::dirs ()->findResourceDir ("data", "rkward/resource.ver") + "rkward/");
 	}
 
+	QString getUseableRKWardSavefileName (const QString &prefix, const QString &postfix) {
+		QDir dir (RKSettingsModuleGeneral::filesPath ());
 
+		int i=0;
+		while (true) {
+			QString candidate = prefix + QString::number (i) + postfix;
+			if (!dir.exists (candidate)) {
+				return dir.filePath (candidate);
+			}
+			i++;
+		}
+	}
+
 	QString escape (const QString &in) {
 		QString out;
 

Modified: trunk/rkward/rkward/misc/rkcommonfunctions.h
===================================================================
--- trunk/rkward/rkward/misc/rkcommonfunctions.h	2010-10-07 10:31:16 UTC (rev 3111)
+++ trunk/rkward/rkward/misc/rkcommonfunctions.h	2010-10-07 14:55:19 UTC (rev 3112)
@@ -2,7 +2,7 @@
                           rkcommonfunctions  -  description
                              -------------------
     begin                : Mon Oct 17 2005
-    copyright            : (C) 2005, 2006, 2007, 2009 by Thomas Friedrichsmeier
+    copyright            : (C) 2005, 2006, 2007, 2009, 2010 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -38,7 +38,10 @@
 
 /** Get the base directory where RKWard data files are stored */
 	QString getRKWardDataDir ();
+/** Get a suitable file name in the RKWard data directory */
+	QString getUseableRKWardSavefileName (const QString &prefix, const QString &postfix);
 
+
 /** given the context line, find what looks like an R symbol */
 	QString getCurrentSymbol (const QString &context_line, int cursor_pos, bool strict=true);
 /** like get current symbol, but merely returns the start and end position of the current symbol */

Modified: trunk/rkward/rkward/rbackend/rembedinternal.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rembedinternal.cpp	2010-10-07 10:31:16 UTC (rev 3111)
+++ trunk/rkward/rkward/rbackend/rembedinternal.cpp	2010-10-07 14:55:19 UTC (rev 3112)
@@ -24,12 +24,14 @@
 #include <QStringList>
 #include <qtextcodec.h>
 #include <klocale.h>
+
 #include "../core/robject.h"
 #include "../debug.h"
 
 #include "rklocalesupport.h"
 #include "rkpthreadsupport.h"
 #include "rksignalsupport.h"
+#include "../misc/rkcommonfunctions.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -233,6 +235,14 @@
 	Rf_error ("Backend dead");	// this jumps us out of the REPL.
 }
 
+void REmbedInternal::tryToDoEmergencySave () {
+	RK_TRACE (RBACKEND);
+
+	// we're probably in a signal handler, and the stack base has changed.
+	R_CStackLimit = (uintptr_t)-1;
+	if (R_DirtyImage) R_SaveGlobalEnvToFile (RKCommonFunctions::getUseableRKWardSavefileName ("rkward_recover", ".RData").toLocal8Bit ());
+}
+
 QStringList charPArrayToQStringList (const char** chars, int count) {
 	QStringList ret;
 	for (int i = 0; i < count; ++i) {
@@ -800,7 +810,7 @@
 
 	setupCallbacks ();
 
-	RKSignalSupport::saveDefaultSigSegvHandler ();
+	RKSignalSupport::saveDefaultSignalHandlers ();
 
 	r_running = true;
 	Rf_initialize_R (argc, argv);
@@ -854,7 +864,7 @@
 	RKWard_RData_Tag = Rf_install ("RKWard_RData_Tag");
 	R_LastvalueSymbol = Rf_install (".Last.value");
 
-	RKSignalSupport::installSigSegvProxy ();
+	RKSignalSupport::installSignalProxies ();
 
 // register our functions
 	R_CallMethodDef callMethods [] = {

Modified: trunk/rkward/rkward/rbackend/rembedinternal.h
===================================================================
--- trunk/rkward/rkward/rbackend/rembedinternal.h	2010-10-07 10:31:16 UTC (rev 3111)
+++ trunk/rkward/rkward/rbackend/rembedinternal.h	2010-10-07 14:55:19 UTC (rev 3112)
@@ -161,6 +161,7 @@
 /** only one instance of this class may be around. This pointer keeps the reference to it, for interfacing to from C to C++ */
 	static REmbedInternal *this_pointer;
 	static char *na_char_internal;
+	static void tryToDoEmergencySave ();
 	bool r_running;
 /** Check whether the runtime version of R is at least the given version. Valid only *after* startR() has been called! */
 	bool RRuntimeIsVersion (int major, int minor, int revision) {

Modified: trunk/rkward/rkward/rbackend/rinterface.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.cpp	2010-10-07 10:31:16 UTC (rev 3111)
+++ trunk/rkward/rkward/rbackend/rinterface.cpp	2010-10-07 14:55:19 UTC (rev 3112)
@@ -137,6 +137,15 @@
 	return (QThread::currentThread () == RKGlobals::rInterface ()->r_thread);
 }
 
+void RInterface::tryToDoEmergencySave () {
+	RK_TRACE (RBACKEND);
+	if (!inRThread ()) {
+		RKGlobals::rInterface ()->r_thread->terminate ();
+		RKGlobals::rInterface ()->r_thread->wait (1000);
+	}
+	RKGlobals::rInterface ()->r_thread->tryToDoEmergencySave ();
+}
+
 void RInterface::startThread () {
 	RK_TRACE (RBACKEND);
 
@@ -317,13 +326,8 @@
 		if (request->call.count () >= 3) {
 			QString file_prefix = request->call[1];
 			QString file_extension = request->call[2];
-			QDir dir (RKSettingsModuleGeneral::filesPath ());
-		
-			int i=0;
-			while (dir.exists (file_prefix + QString::number (i) + file_extension)) {
-				i++;
-			}
-			issueCommand (".rk.set.reply (\"" + dir.filePath (file_prefix + QString::number (i) + file_extension) + "\")", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
+
+			issueCommand (".rk.set.reply (\"" + RKCommonFunctions::getUseableRKWardSavefileName (file_prefix, file_extension) + "\")", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
 		} else {
 			issueCommand (".rk.set.reply (\"Too few arguments in call to get.tempfile.name.\")", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
 		}

Modified: trunk/rkward/rkward/rbackend/rinterface.h
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.h	2010-10-07 10:31:16 UTC (rev 3111)
+++ trunk/rkward/rkward/rbackend/rinterface.h	2010-10-07 14:55:19 UTC (rev 3112)
@@ -92,6 +92,7 @@
 	bool backendIsIdle ();
 
 	static bool inRThread ();
+	static void tryToDoEmergencySave ();
 public slots:
 /** called periodically to flush output buffer in RThread */
 	void flushOutput ();

Modified: trunk/rkward/rkward/rbackend/rksignalsupport.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rksignalsupport.cpp	2010-10-07 10:31:16 UTC (rev 3111)
+++ trunk/rkward/rkward/rbackend/rksignalsupport.cpp	2010-10-07 14:55:19 UTC (rev 3112)
@@ -2,7 +2,7 @@
                           rksignalsupport  -  description
                              -------------------
     begin                : Thu Nov 22 2007
-    copyright            : (C) 2007, 2009 by Thomas Friedrichsmeier
+    copyright            : (C) 2007, 2009, 2010 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -33,84 +33,118 @@
 #ifdef Q_WS_WIN
 	__sighandler_t r_sigsegv_handler = 0;
 	__sighandler_t default_sigsegv_handler = 0;
+	__sighandler_t r_sigill_handler = 0;
+	__sighandler_t default_sigill_handler = 0;
+	__sighandler_t r_sigabrt_handler = 0;
+	__sighandler_t default_sigabrt_handler = 0;
+#else
+	struct sigaction r_sigsegv_handler;
+	struct sigaction default_sigsegv_handler;
+	struct sigaction r_sigill_handler;
+	struct sigaction default_sigill_handler;
+	struct sigaction r_sigabrt_handler;
+	struct sigaction default_sigabrt_handler;
+#endif
 
-	void sigsegv_proxy (int signum) {
+#ifdef Q_WS_WIN
+	void signal_proxy (int signum) {
+		__sighandler_t r_handler = r_sigsegv_handler;
+		__sighandler_t default_handler = default_sigsegv_handler;
 #else
-	struct sigaction r_sigsegv_action;
-	struct sigaction default_sigsegv_action;
+	void signal_proxy (int signum, siginfo_t *info, void *context) {
+		struct sigaction r_handler = r_sigsegv_handler;
+		struct sigaction default_handler = default_sigsegv_handler;
+#endif
+		if (signum == SIGILL) {
+			r_handler = r_sigill_handler;
+			default_handler = default_sigill_handler;
+		} else if (signum == SIGABRT) {
+			r_handler = r_sigabrt_handler;
+			default_handler = default_sigabrt_handler;
+		} else {
+			RK_ASSERT (signum == SIGSEGV);
+		}
 
-	void sigsegv_proxy (int signum, siginfo_t *info, void *context) {
-#endif
-		RK_ASSERT (signum == SIGSEGV);
-	
+		RInterface::tryToDoEmergencySave ();
+
 		// if we are not in the R thread, handling the signal in R does more harm than good.
 		if (RInterface::inRThread ()) {
 #ifdef Q_WS_WIN
-			if (r_sigsegv_handler) {
-				r_sigsegv_handler (signum);
+			if (r_handler) {
+				r_handler (signum);
 				return;
 			}
 #else
-			if (r_sigsegv_action.sa_sigaction) {
-				r_sigsegv_action.sa_sigaction (signum, info, context);
+			if (r_handler.sa_sigaction) {
+				r_handler.sa_sigaction (signum, info, context);
 				return;
-			} else if (r_sigsegv_action.sa_handler) {
-				r_sigsegv_action.sa_handler (signum);
+			} else if (r_handler.sa_handler) {
+				r_handler.sa_handler (signum);
 				return;
 			}
 #endif
 		}
 
 #ifdef Q_WS_WIN
-		if (default_sigsegv_handler) {
-			default_sigsegv_handler (signum);
+		if (default_handler) {
+			default_handler (signum);
 			return;
 		}
 #else
 		// this might be a Qt/KDE override or default handling
-		if (default_sigsegv_action.sa_sigaction) {
-			default_sigsegv_action.sa_sigaction (signum, info, context);
+		if (default_handler.sa_sigaction) {
+			default_handler.sa_sigaction (signum, info, context);
 			return;
-		} else if (default_sigsegv_action.sa_handler) {
-			default_sigsegv_action.sa_handler (signum);
+		} else if (default_handler.sa_handler) {
+			default_handler.sa_handler (signum);
 			return;
 		}
 #endif
-
-		// not handled? should not happen
-		RK_ASSERT (false);
-
-		// do the default fallback handling
-		signal (SIGSEGV, SIG_DFL);
-		raise (SIGSEGV);
 	}
 }
 
-void RKSignalSupport::saveDefaultSigSegvHandler () {
+void RKSignalSupport::saveDefaultSignalHandlers () {
 	RK_TRACE (RBACKEND);
 
 #ifdef Q_WS_WIN
 	RKSignalSupportPrivate::default_sigsegv_handler = signal (SIGSEGV, SIG_DFL);
+	RKSignalSupportPrivate::default_sigill_handler = signal (SIGILL, SIG_DFL);
+	RKSignalSupportPrivate::default_sigabrt_handler = signal (SIGABRT, SIG_DFL);
 #else
-	sigaction (SIGSEGV, 0, &RKSignalSupportPrivate::default_sigsegv_action);
+	sigaction (SIGSEGV, 0, &RKSignalSupportPrivate::default_sigsegv_handler);
+	sigaction (SIGILL, 0, &RKSignalSupportPrivate::default_sigill_handler);
+	sigaction (SIGABRT, 0, &RKSignalSupportPrivate::default_sigabrt_handler);
 #endif
 }
 
-void RKSignalSupport::installSigSegvProxy () {
+void RKSignalSupport::installSignalProxies () {
 	RK_TRACE (RBACKEND);
 
 #ifdef Q_WS_WIN
-	RKSignalSupportPrivate::r_sigsegv_handler = signal (SIGSEGV, &RKSignalSupportPrivate::sigsegv_proxy);
+	RKSignalSupportPrivate::r_sigsegv_handler = signal (SIGSEGV, &RKSignalSupportPrivate::signal_proxy);
+	RKSignalSupportPrivate::r_sigill_handler = signal (SIGILL, &RKSignalSupportPrivate::signal_proxy);
+	RKSignalSupportPrivate::r_sigabrt_handler = signal (SIGABRT, &RKSignalSupportPrivate::signal_proxy);
 #else
 	// retrieve R signal handler
-	sigaction (SIGSEGV, 0, &RKSignalSupportPrivate::r_sigsegv_action);
+	sigaction (SIGSEGV, 0, &RKSignalSupportPrivate::r_sigsegv_handler);
+	sigaction (SIGILL, 0, &RKSignalSupportPrivate::r_sigill_handler);
+	sigaction (SIGABRT, 0, &RKSignalSupportPrivate::r_sigabrt_handler);
 
+	// set new proxy handlers
 	struct sigaction proxy_action;
-	proxy_action = RKSignalSupportPrivate::r_sigsegv_action;
+	proxy_action = RKSignalSupportPrivate::r_sigsegv_handler;
 	proxy_action.sa_flags |= SA_SIGINFO;
-	proxy_action.sa_sigaction = &RKSignalSupportPrivate::sigsegv_proxy;
+	proxy_action.sa_sigaction = &RKSignalSupportPrivate::signal_proxy;
+	sigaction (SIGSEGV, &proxy_action, 0);
 
-	// set new proxy handler
-	sigaction (SIGSEGV, &proxy_action, 0);
+	proxy_action = RKSignalSupportPrivate::r_sigill_handler;
+	proxy_action.sa_flags |= SA_SIGINFO;
+	proxy_action.sa_sigaction = &RKSignalSupportPrivate::signal_proxy;
+	sigaction (SIGILL, &proxy_action, 0);
+
+	proxy_action = RKSignalSupportPrivate::default_sigabrt_handler;
+	proxy_action.sa_flags |= SA_SIGINFO;
+	proxy_action.sa_sigaction = &RKSignalSupportPrivate::signal_proxy;
+	sigaction (SIGABRT, &proxy_action, 0);
 #endif
 }

Modified: trunk/rkward/rkward/rbackend/rksignalsupport.h
===================================================================
--- trunk/rkward/rkward/rbackend/rksignalsupport.h	2010-10-07 10:31:16 UTC (rev 3111)
+++ trunk/rkward/rkward/rbackend/rksignalsupport.h	2010-10-07 14:55:19 UTC (rev 3112)
@@ -2,7 +2,7 @@
                           rksignalsupport  -  description
                              -------------------
     begin                : Thu Nov 22 2007
-    copyright            : (C) 2007 by Thomas Friedrichsmeier
+    copyright            : (C) 2007, 2010 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -19,8 +19,8 @@
 #define RKSIGNALSUPPORT_H
 
 namespace RKSignalSupport {
-	void saveDefaultSigSegvHandler ();
-	void installSigSegvProxy ();
+	void saveDefaultSignalHandlers ();
+	void installSignalProxies ();
 };
 
 #endif


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