@@ -54,20 +54,34 @@ inline void set_option(SEXP name, SEXP value) {
54
54
SETCAR (opt, value);
55
55
}
56
56
57
- inline Rboolean& get_should_unwind_protect () {
57
+ inline Rboolean* setup_should_unwind_protect () {
58
58
SEXP should_unwind_protect_sym = Rf_install (" cpp11_should_unwind_protect" );
59
59
SEXP should_unwind_protect_sexp = Rf_GetOption1 (should_unwind_protect_sym);
60
+
60
61
if (should_unwind_protect_sexp == R_NilValue) {
62
+ // Allocate and initialize once, then let R manage it.
63
+ // That makes this a shared global across all compilation units.
61
64
should_unwind_protect_sexp = PROTECT (Rf_allocVector (LGLSXP, 1 ));
65
+ SET_LOGICAL_ELT (should_unwind_protect_sexp, 0 , TRUE );
62
66
detail::set_option (should_unwind_protect_sym, should_unwind_protect_sexp);
63
67
UNPROTECT (1 );
64
68
}
65
69
66
- Rboolean* should_unwind_protect =
67
- reinterpret_cast <Rboolean*>(LOGICAL (should_unwind_protect_sexp));
68
- should_unwind_protect[0 ] = TRUE ;
70
+ return reinterpret_cast <Rboolean*>(LOGICAL (should_unwind_protect_sexp));
71
+ }
72
+
73
+ inline Rboolean* access_should_unwind_protect () {
74
+ // Setup is run once per compilation unit, but all compilation units
75
+ // share the same global option, so each compilation unit's static pointer
76
+ // will point to the same object.
77
+ static Rboolean* p_should_unwind_protect = setup_should_unwind_protect ();
78
+ return p_should_unwind_protect;
79
+ }
80
+
81
+ inline Rboolean get_should_unwind_protect () { return *access_should_unwind_protect (); }
69
82
70
- return should_unwind_protect[0 ];
83
+ inline void set_should_unwind_protect (Rboolean should_unwind_protect) {
84
+ *access_should_unwind_protect () = should_unwind_protect;
71
85
}
72
86
73
87
} // namespace detail
@@ -80,12 +94,11 @@ inline Rboolean& get_should_unwind_protect() {
80
94
template <typename Fun, typename = typename std::enable_if<std::is_same<
81
95
decltype (std::declval<Fun&&>()()), SEXP>::value>::type>
82
96
SEXP unwind_protect(Fun&& code) {
83
- static auto should_unwind_protect = detail::get_should_unwind_protect ();
84
- if (should_unwind_protect == FALSE ) {
97
+ if (detail::get_should_unwind_protect () == FALSE ) {
85
98
return std::forward<Fun>(code)();
86
99
}
87
100
88
- should_unwind_protect = FALSE ;
101
+ detail::set_should_unwind_protect ( FALSE ) ;
89
102
90
103
static SEXP token = [] {
91
104
SEXP res = R_MakeUnwindCont ();
@@ -95,7 +108,7 @@ SEXP unwind_protect(Fun&& code) {
95
108
96
109
std::jmp_buf jmpbuf;
97
110
if (setjmp (jmpbuf)) {
98
- should_unwind_protect = TRUE ;
111
+ detail::set_should_unwind_protect ( TRUE ) ;
99
112
throw unwind_exception (token);
100
113
}
101
114
@@ -120,7 +133,7 @@ SEXP unwind_protect(Fun&& code) {
120
133
// unset it here before returning the value ourselves.
121
134
SETCAR (token, R_NilValue);
122
135
123
- should_unwind_protect = TRUE ;
136
+ detail::set_should_unwind_protect ( TRUE ) ;
124
137
125
138
return res;
126
139
}
0 commit comments