Skip to content

Commit 005b455

Browse files
committed
New checkUserInterrupt function that provides a C++ friendly implementation of R_CheckUserInterrupt
1 parent d74f29f commit 005b455

File tree

6 files changed

+96
-5
lines changed

6 files changed

+96
-5
lines changed

ChangeLog

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
2014-01-03 JJ Allaire <jj@rstudio.org>
22

3-
* Added src/<object-files>, *.Rproj, and .Rproj.user to .gitignore
4-
3+
* .gitignore: Added src/<object-files>, *.Rproj, and .Rproj.user
4+
* inst/include/Rcpp/Interrupt.h: New checkUserInterrupt function
5+
that provides a C++ friendly implementation of R_CheckUserInterrupt
6+
* inst/include/RcppCommon.h: Include Rcpp/Interrupts.h
7+
* inst/include/macros/macros.h: Check for interrupts in END_RCPP
8+
* src/attributes.cpp: Handle interrupted-error in attribute
9+
function envelope.
10+
511
2013-12-31 Dirk Eddelbuettel <edd@debian.org>
612

713
* vignettes/Rcpp.bib: Updated CRAN package references

inst/NEWS.Rd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
and \code{NaN}.)
2222
\item Applied two bug fixes to Vector \code{sort()} and \code{RObject}
2323
definition spotted and correct by Kevin Ushey
24+
\item New \code{checkUserInterrupt()} function that provides a C++ friendly
25+
implementation of \code{R_CheckUserInterrupt}.
2426
}
2527
\item Changes in Rcpp documentation:
2628
\itemize{

inst/include/Rcpp/Interrupt.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2+
//
3+
// Interrupt.h: Rcpp R/C++ interface class library -- check for interrupts
4+
//
5+
// Copyright (C) 2009 - 2013 Dirk Eddelbuettel and Romain Francois
6+
//
7+
// This file is part of Rcpp.
8+
//
9+
// Rcpp is free software: you can redistribute it and/or modify it
10+
// under the terms of the GNU General Public License as published by
11+
// the Free Software Foundation, either version 2 of the License, or
12+
// (at your option) any later version.
13+
//
14+
// Rcpp is distributed in the hope that it will be useful, but
15+
// WITHOUT ANY WARRANTY; without even the implied warranty of
16+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
// GNU General Public License for more details.
18+
//
19+
// You should have received a copy of the GNU General Public License
20+
// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
21+
22+
#ifndef Rcpp_Interrupt_h
23+
#define Rcpp_Interrupt_h
24+
25+
#include <Rinterface.h>
26+
27+
namespace Rcpp {
28+
29+
// Internal functions used in the implementation of checkUserInterrupt
30+
namespace internal {
31+
32+
// Sentinel class for communicating interrupts to the top-level END_RCPP macro
33+
class InterruptedException {};
34+
35+
// Sentinel object of class "interrupted-error" which is used for
36+
// communicating interrupts accross module boundaries without an
37+
// exception (which would crash on windows). This is identical to
38+
// the existing "try-error" sentinel object used for communicating
39+
// errors accross module boundaries.
40+
inline SEXP interruptedError() {
41+
Rcpp::Shield<SEXP> interruptedError( Rf_mkString("") );
42+
Rf_setAttrib( interruptedError, R_ClassSymbol, Rf_mkString("interrupted-error") ) ;
43+
return interruptedError;
44+
}
45+
46+
// Interrupt R's execution by jumping to the top-level
47+
inline void jumpToTop() {
48+
Rf_jump_to_toplevel();
49+
}
50+
51+
} // namespace internal
52+
53+
// Helper function to check for interrupts. This is invoked within
54+
// R_ToplevelExec so it doesn't longjmp
55+
namespace {
56+
57+
inline void checkInterruptFn(void *dummy) {
58+
R_CheckUserInterrupt();
59+
}
60+
61+
} // anonymous namespace
62+
63+
// Check for interrupts and throw the sentinel exception if one is pending
64+
inline void checkUserInterrupt() {
65+
if (R_ToplevelExec(checkInterruptFn, NULL) == FALSE)
66+
throw internal::InterruptedException();
67+
}
68+
69+
} // namespace Rcpp
70+
71+
#endif

inst/include/Rcpp/macros/macros.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@
3131
#endif
3232

3333
#ifndef VOID_END_RCPP
34-
#define VOID_END_RCPP } catch( std::exception& __ex__ ){ forward_exception_to_r( __ex__ ) ; } catch(...){ ::Rf_error( "c++ exception (unknown reason)" ) ; }
34+
#define VOID_END_RCPP } catch( Rcpp::internal::InterruptedException& __ex__ ) { Rcpp::internal::jumpToTop(); } catch( std::exception& __ex__ ){ forward_exception_to_r( __ex__ ) ; } catch(...){ ::Rf_error( "c++ exception (unknown reason)" ) ; }
3535
#endif
3636

3737
#ifndef END_RCPP
3838
#define END_RCPP VOID_END_RCPP return R_NilValue;
3939
#endif
4040

4141
#ifndef END_RCPP_RETURN_ERROR
42-
#define END_RCPP_RETURN_ERROR } catch( std::exception& __ex__ ){ return exception_to_try_error( __ex__ ) ; } catch(...){ return string_to_try_error( "c++ exception (unknown reason)" ) ; } return R_NilValue;
42+
#define END_RCPP_RETURN_ERROR } catch( Rcpp::internal::InterruptedException& __ex__ ) { return Rcpp::internal::interruptedError(); } catch( std::exception& __ex__ ){ return exception_to_try_error( __ex__ ) ; } catch(...){ return string_to_try_error( "c++ exception (unknown reason)" ) ; } return R_NilValue;
4343
#endif
4444

4545
#define Rcpp_error(MESSAGE) throw Rcpp::exception( MESSAGE, __FILE__, __LINE__ )

inst/include/RcppCommon.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ namespace Rcpp{
139139

140140
#include <Rcpp/exceptions.h>
141141

142+
#include <Rcpp/Interrupt.h>
143+
142144
namespace Rcpp{
143145
template <typename T> class object ;
144146
class String ;

src/attributes.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,10 @@ namespace attributes {
17001700
ostr() << ");" << std::endl;
17011701
ostr() << " }" << std::endl;
17021702

1703+
ostr() << " if (__result.inherits(\"interrupted-error\"))"
1704+
<< std::endl
1705+
<< " throw Rcpp::internal::InterruptedException();"
1706+
<< std::endl;
17031707
ostr() << " if (__result.inherits(\"try-error\"))"
17041708
<< std::endl
17051709
<< " throw Rcpp::exception(as<std::string>("
@@ -2222,7 +2226,13 @@ namespace attributes {
22222226
}
22232227
ostr << "));" << std::endl;
22242228
ostr << " }" << std::endl;
2225-
ostr << " Rboolean __isError = Rf_inherits(__result, \"try-error\");"
2229+
ostr << " Rboolean __isInterrupt = Rf_inherits(__result, \"interrupted-error\");"
2230+
<< std::endl
2231+
<< " if (__isInterrupt) {" << std::endl
2232+
<< " UNPROTECT(1);" << std::endl
2233+
<< " Rcpp::internal::jumpToTop();" << std::endl
2234+
<< " }" << std::endl
2235+
<< " Rboolean __isError = Rf_inherits(__result, \"try-error\");"
22262236
<< std::endl
22272237
<< " if (__isError) {" << std::endl
22282238
<< " SEXP __msgSEXP = Rf_asChar(__result);" << std::endl

0 commit comments

Comments
 (0)