'Segfault when running R callback function from C++ after completing a task on a background thread
The following code (seems to) work as expected, but I receive a segfault if I remove the PROTECT call or if I remove the second member expr of struct func_data.
This seems like it could be related to garbage collection of the callback function. But I read that Rcpp automatically protects RObjects from GC.
The segfault is received when calling the function from R using the expression listenOn("/home/cld/tmp/test", function() cat("triggered\n"))
#include <uv.h>
#include <Rcpp.h>
#include <later_api.h>
struct func_data {
Rcpp::Function func;
SEXP expr; // FIXME: We get a segfault if we remove this
};
void on_fs_event(uv_fs_event_t *handle, const char *filename, int events, int status) {
uv_fs_event_stop(handle);
return;
}
class Listen : public later::BackgroundTask {
public:
Listen(const char* _path, void *_callback_data_ptr) :
path(_path),
callback_data_ptr((struct func_data *) _callback_data_ptr)
{ }
protected:
void execute() {
uv_loop_t *loop = uv_default_loop();
uv_fs_event_t *fs_event_req = (uv_fs_event_t *) malloc(sizeof(uv_fs_event_t));
uv_fs_event_init(loop, fs_event_req);
uv_fs_event_start(fs_event_req, on_fs_event, path, UV_FS_EVENT_RECURSIVE);
uv_run(loop, UV_RUN_ONCE);
}
void complete() {
(new Listen(path, (void *) callback_data_ptr))->begin();
callback_data_ptr->func();
}
private:
const char* path;
struct func_data *callback_data_ptr;
};
// [[Rcpp::export]]
void listenOn(const char* path, Rcpp::Function callback) {
PROTECT(callback); //FIXME: We get a segfault if we remove this. Is this necessary when dealing with a Rcpp::Function?
struct func_data callback_data = { callback };
(new Listen(path, (void *) &callback_data))->begin();
}
For completeness, here is my RcppExports.cpp file.
// Generated by using Rcpp::compileAttributes() -> do not edit by hand
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
#include <Rcpp.h>
using namespace Rcpp;
class FuncWrap {
public:
FuncWrap(SEXP func_)
: wrap(func_)
{ }
private:
Rcpp::RObject wrap;
};
#ifdef RCPP_USE_GLOBAL_ROSTREAM
Rcpp::Rostream<true>& Rcpp::Rcout = Rcpp::Rcpp_cout_get();
Rcpp::Rostream<false>& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get();
#endif
void listenOn(const char* path, Rcpp::Function callback);
RcppExport SEXP _fileuv_listenOn(SEXP s_path, SEXP s_callback) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< const char * >::type path(s_path);
Rcpp::traits::input_parameter< Rcpp::Function >::type callback(s_callback);
listenOn(path, callback);
END_RCPP
}
static const R_CallMethodDef CallEntries[] = {
{"_fileuv_listenOn", (DL_FUNC) &_fileuv_listenOn, 0},
{NULL, NULL, 0}
};
RcppExport void R_init_fileuv(DllInfo *dll) {
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
