Using a pointer to Isolate in libuv worker thread - c++

I try to develop an async Node.js addon that works with an Isolate.
Consider this example code:
struct Work {
uv_work_t request;
Persistent<Function> callback;
Isolate * isolate;
};
// called in worker thread
static void WorkAsync(uv_work_t *req)
{
Work *work = static_cast<Work *>(req->data);
HeapStatistics stats;
work->isolate->GetHeapStatistics(&stats);
// ... do other stuff ...
}
// called by in main thread
static void WorkAsyncComplete(uv_work_t *req, int status)
{
Isolate * isolate = Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
Work *work = static_cast<Work *>(req->data);
// ... do other stuff ...
work->callback.Reset();
delete work;
}
void RunAsync(const v8::FunctionCallbackInfo<v8::Value>&args) {
Isolate* isolate = args.GetIsolate();
Work * work = new Work();
work->request.data = work;
work->isolate = isolate;
Local<Function> callback = Local<Function>::Cast(args[0]);
work->callback.Reset(isolate, callback);
// kick of the worker thread
uv_queue_work(uv_default_loop(), &work->request, WorkAsync, WorkAsyncComplete);
args.GetReturnValue().Set(Undefined(isolate));
}
void setup(Handle <Object> exports, Handle<Object> module) {
NODE_SET_METHOD(exports, "run", RunAsync);
}
NODE_MODULE(addon, setup)
My question: is it safe to pass a pointer to current Isolate to a worker thread (for read-only purposes)?
Thanks!

Answered by Scott Frees (the author of C++ and Node.js Integration ebook: https://scottfrees.com/ebooks/nodecpp/):
To be honest, I've never tried to do that. It seems to me that it should be fine - as long as you are only making calls on the isolate and not actually modifying anything within it.
Generally, if you try to do anything in violation with the V8 threading model, it will generate an exception - so if it's not, then I'd assume it is ok.

Yes it's possible. However, you are the responsable of the safety. You need to be sure that Isolate is leaved from the parent thread and unlocked. Then it can be used (Entred) in the worker thread.

Related

how to implement node-nan callback using node-addon-api

Until now I've only implemented synchronous node-addon-api methods, i.e., a JavaScript function makes a call, work is done, and the addon returns. I have big gaps in knowledge when it comes to the inner workings of v8, libuv, and node, so please correct any obvious misconceptions.
The goal is to call a JavaScript callback when C++ garbage collection callbacks are called from v8. I originally just called the JavaScript callback from the v8 garbage collection callback but that ended up with a segv after a couple calls. It seems that just making a call into JavaScript while being called from a v8 callback has some problems (v8 docs the callbacks shouldn't allocate objects). So I looked around and found a Nan-based example that uses libuv and Nan's AsyncResource to make the callback. The following approach works using node-nan:
NAN_GC_CALLBACK(afterGC) {
uint64_t et = uv_hrtime() - gcStartTime;
// other bookkeeping for GCData_t raw.
if (doCallbacks) {
uv_async_t* async = new uv_async_t;
GCData_t* data = new GCData_t;
*data = raw;
data->gcTime = et;
async->data = data;
uv_async_init(uv_default_loop(), async, asyncCB);
uv_async_send(async);
}
}
class GCResponseResource : public Nan::AsyncResource {
public:
GCResponseResource(Local<Function> callback_)
: Nan::AsyncResource("nan:gcstats.DeferredCallback") {
callback.Reset(callback_);
}
~GCResponseResource() {
callback.Reset();
}
Nan::Persistent<Function> callback;
};
static GCResponseResource* asyncResource;
static void closeCB(uv_handle_t *handle) {
delete handle;
}
static void asyncCB(uv_async_t *handle) {
Nan::HandleScope scope;
GCData_t* data = static_cast<GCData_t*>(handle->data);
Local<Object> obj = Nan::New<Object>();
Nan::Set(obj, Nan::New("gcCount").ToLocalChecked(),
Nan::New<Number>((data->gcCount));
Nan::Set(obj, Nan::New("gcTime").ToLocalChecked(),
Nan::New<Number>(data->gcTime));
Local<Object> counts = Nan::New<v8::Object>();
for (int i = 0; i < maxTypeCount; i++) {
if (data->typeCounts[i] != 0) {
Nan::Set(counts, i, Nan::New<Number>(data->typeCounts[i]));
}
}
Nan::Set(obj, Nan::New("gcTypeCounts").ToLocalChecked(), counts);
Local<Value> arguments[] = {obj};
Local<Function> callback = Nan::New(asyncResource->callback);
v8::Local<v8::Object> target = Nan::New<v8::Object>();
asyncResource->runInAsyncScope(target, callback, 1, arguments);
delete data;
uv_close((uv_handle_t*) handle, closeCB);
}
My question is how would I do this using the node-addon-api instead of nan?
It's not clear to me what the node-addon-api equivalent of uv_async_init, uv_async_send, etc are. This is partially because it's not clear to me what underlying N-API (as opposed to node-addon-api) functions are required.
I have been unable to find an example like this. The callback example is completely synchronous. The async pi example uses a worker thread to perform a task but that seems overkill compared to the approach in the nan-based code using the uv primitives.
Your example is not really asynchronous, because the GC callbacks run in the main thread. However when the JS world is stopped because of the GC, this does not mean that it is stopped in a way allowing a callback to run - as the GC can stop it in the middle of a function.
You need a ThreadSafeFunction to do this. Look here for an example:
https://github.com/nodejs/node-addon-api/blob/main/doc/threadsafe_function.md

Get std::thread's thread:id before it runs?

I'm trying to build a thread-safety layer on top of C++ 11's std::thread where each object is assigned to an owning thread, and certain calls can raise a hard error when they are used on the wrong thread. The owning thread is the only one that can transfer an object to another thread.
I have it all working, except that I can't find a way to get a thread's thread::id before it is actually running. And I need to attach the new thread's ID to the object before I hand it off.
If I use
std::thread newThread( [theObject]()
{
// use theObject here.
} );
The earliest point I can get the thread's ID is after the definition of the thread object, at which point the thread is already running.
I see there is a default constructor for std::thread, but I can't see a way to give it a function to run on the thread afterwards.
Is there a way to perform two-step construction on a thread, or control the thread's ID at time of creation?
Rather than getting the ID of the thread before it starts running, you could consider having the function the thread executes do some initial setup before taking off. For example, you could do something like this:
bool isReady = false;
bool wasReceived = false;
std::mutex mutex;
std::condition_variable condition;
std::thread newThread([theObject, &isReady, &mutex, &condition] {
/* Wait until we've been cleared to go. */
std::unique_lock<std::mutex> lock(isReady);
condition.wait(lock, [&isReady] { return isReady; });
/* Signal that we're done. */
wasReceived = true;
lock.unlock();
condition.notify_one();
/* Put code here to do whatever it is that the thread should do. */
});
/* Read the thread's ID. It's currently waiting for us. */
auto id = newThread.get_id();
/* Tell the thread that we're ready for it. */
std::unique_lock<std::mutex> lock(mutex);
isReady = true;
condition.notify_one();
/* Wait until the thread has confirmed that it's ready. */
condition.wait(lock, [&] { return wasReceived; });
This creates the thread and has it sit and wait until the creator has a chance to read its ID. Once that's happened, the creator then waits until the thread confirms that it's ready to go, and from there you can work with the thread ID however you'd like.
Beware of bugs in the above code - it's completely untested. :-)
No--as soon as you create a thread, it starts to run. If you want to get its ID before it does (much of) anything, you probably want to create a little wrapper, where you pass the thread (for example) a CV and a queue where it deposits its output.
Then when the thread starts up, it retrieves its own ID, deposits it in the output queue, and then waits on the CV. When the parent has retrieved the ID, and is ready for the child to start doing something, it signals the CV, and off it goes.
Start each thread inactived by passing a unique std::promise parameter, get the thread id first ( thread id is used as a pass by reference parameter for the purpose) afterwards let it wait for the promise to be set by the thread manager. This will also remove the hassle of using a conditional variable.
Edited Snippet
class smart_thread {
public:
smart_thread(std::function<void(void)> task)
{
thread_ = std::thread([=]() {
id_ = std::this_thread::get_id();
// wait here till activated
future_.get();
if(active_) task();
});
}
void activate() {
promise_.set_value();
active_ = true;
}
~smart_thread() {
if(!active_) promise_.set_value();
thread_.join();
}
private:
std::thread::id id_;
std::atomic<bool> active_ = false;
std::thread thread_;
std::promise<void> promise_;
std::future<void> future_ = promise_.get_future();
};
void main()
{
auto task = []() { std::cout << "Hello World\n"; };
smart_thread thread(task); // start thread inactive mode
thread.activate(); // activate thread
}
Would it be possible to create a template class that accepts the thread routine in the form of a std::function<void(T *object)>. This can easily be done with an anonymous closure if additional parameters need to be passed in.
template <class T>
class ThreadWrapper
{
public:
ThreadWrapper(std::function<void(T *object)> function, T *object) :
{
m_thread = std::thread(WrapFunction, function, object);
//optionally
m_thread.detach();
}
static void WrapFunction(ThreadWrapper *wrapper, std::function<void()> function, T *object)
{
// Get the thread id and save in the object
object->SetThreadId(get_id());
// Now actually invoke the thread routine, with the id already installed.
function(object);
}
}
// Cleanup is left as an exercise for the reader.
Beware of bugs in the above code - it's completely untested. :-) :-)

Can POSIX timers safely modify C++ STL objects?

I'm attempting to write a C++ "wrapper" for the POSIX timer system on Linux, so that my C++ program can set timeouts for things (such as waiting for a message to arrive over the network) using the system clock, without dealing with POSIX's ugly C interface. It seems to work most of the time, but occasionally my program will segfault after several minutes of running successfully. The problem seems to be that my LinuxTimerManager object (or one of its member objects) gets its memory corrupted, but unfortunately the problem refuses to appear if I run the program under Valgrind, so I'm stuck staring at my code to try to figure out what's wrong with it.
Here's the core of my timer-wrapper implementation:
LinuxTimerManager.h:
namespace util {
using timer_id_t = int;
class LinuxTimerManager {
private:
timer_id_t next_id;
std::map<timer_id_t, timer_t> timer_handles;
std::map<timer_id_t, std::function<void(void)>> timer_callbacks;
std::set<timer_id_t> cancelled_timers;
friend void timer_signal_handler(int signum, siginfo_t* info, void* ucontext);
public:
LinuxTimerManager();
timer_id_t register_timer(const int delay_ms, std::function<void(void)> callback);
void cancel_timer(const timer_id_t timer_id);
};
void timer_signal_handler(int signum, siginfo_t* info, void* ucontext);
}
LinuxTimerManager.cpp:
namespace util {
LinuxTimerManager* tm_instance;
LinuxTimerManager::LinuxTimerManager() : next_id(0) {
tm_instance = this;
struct sigaction sa = {0};
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = timer_signal_handler;
sigemptyset(&sa.sa_mask);
int success_flag = sigaction(SIGRTMIN, &sa, NULL);
assert(success_flag == 0);
}
void timer_signal_handler(int signum, siginfo_t* info, void* ucontext) {
timer_id_t timer_id = info->si_value.sival_int;
auto cancelled_location = tm_instance->cancelled_timers.find(timer_id);
//Only fire the callback if the timer is not in the cancelled set
if(cancelled_location == tm_instance->cancelled_timers.end()) {
tm_instance->timer_callbacks.at(timer_id)();
} else {
tm_instance->cancelled_timers.erase(cancelled_location);
}
tm_instance->timer_callbacks.erase(timer_id);
timer_delete(tm_instance->timer_handles.at(timer_id));
tm_instance->timer_handles.erase(timer_id);
}
timer_id_t LinuxTimerManager::register_timer(const int delay_ms, std::function<void(void)> callback) {
struct sigevent timer_event = {0};
timer_event.sigev_notify = SIGEV_SIGNAL;
timer_event.sigev_signo = SIGRTMIN;
timer_event.sigev_value.sival_int = next_id;
timer_t timer_handle;
int success_flag = timer_create(CLOCK_REALTIME, &timer_event, &timer_handle);
assert(success_flag == 0);
timer_handles[next_id] = timer_handle;
timer_callbacks[next_id] = callback;
struct itimerspec timer_spec = {0};
timer_spec.it_interval.tv_sec = 0;
timer_spec.it_interval.tv_nsec = 0;
timer_spec.it_value.tv_sec = 0;
timer_spec.it_value.tv_nsec = delay_ms * 1000000;
timer_settime(timer_handle, 0, &timer_spec, NULL);
return next_id++;
}
void LinuxTimerManager::cancel_timer(const timer_id_t timer_id) {
if(timer_handles.find(timer_id) != timer_handles.end()) {
cancelled_timers.emplace(timer_id);
}
}
}
When my program crashes, the segfault always comes from timer_signal_handler(), usually the lines tm_instance->timer_callbacks.erase(timer_id) or tm_instance->timer_handles.erase(timer_id). The actual segfault is thrown from somewhere deep in the std::map implementation (i.e. stl_tree.h).
Could my memory corruption be caused by a race condition between different timer signals modifying the same LinuxTimerManager? I thought only one timer signal was delivered at a time, but maybe I misunderstood the man pages. Is it just generally unsafe to make a Linux signal handler modify a complex C++ object like std::map?
The signal can occur in the middle of e.g. malloc or free and thus most calls which do interesting things with containers could result in reentering the memory allocation support while its data structures are in an arbitrary state. (As pointed out in the comments, most functions are not safe to call in asynchronous signal handlers. malloc and free are just examples.) Reentering a component in this fashion leads to pretty much arbitrary failure.
Libraries cannot be made safe against this behavior without blocking signals for the entire process during any operations within the library. Doing that is prohibitively expensive, both in the overhead of managing the signal mask and in the amount of time signals would be blocked. (It has to be for the entire process as a signal handler should not block on locks. If a thread handling a signal calls into a library protected by mutexes while another thread holds a mutex the signal handler needs, the handler will block. It is very hard to avoid deadlock when this can happen.)
Designs which work around this typically have a thread which listens for specific event and then does the processing. You have to use semaphores to synchronize between the thread and the signal handler.

How to use Thread to run a class Constructor

Is there a way to construct a class with specific parameters in a separate thread?
In the examples I have seen I can only see thread running functions and member functions. To be more specific, I would need it to run this constructor in a separate thread:
Thermistor(ukd_Adc * pAdc,
const lookup_table_t * pLUT,
uint8_t numOfLutElements);
I want to construct the class in a different thread to assert functionality and check for edge cases.
If there is an edge case like the pointer to ukd_Adc being NULL, the assert will make it hang in an infinite loop. This thread will allow me to set a time limit on how long the constructor may run so it does not go into an infinite loop.
This is for testing purposes since google test does not have a timeout feature to my knowledge.
If you simply want to construct an object on a separate thread and check if it has successfully finished within a specific time constrain, use:
int main() {
std::promise<std::shared_ptr<Thermistor>> promise;
std::future<std::shared_ptr<Thermistor>> future = promise.get_future();
std::thread([&promise](ukd_Adc * pAdc,
const lookup_table_t * pLUT,
uint8_t numOfLutElements) {
promise.set_value_at_thread_exit(std::make_shared<Thermistor>(pAdc, pLUT, numOfLutElements));
}, <pAdc-value>, <pLUT-value>, <numOfLutElements-value>).detach();
auto status = future.wait_for(std::chrono::seconds(3));
if (status == std::future_status::ready)
{
// succeeded
}
else
{
// failed
}
}
You can use the alarm() function to raise a signal (SIGALRM) after a specified amount of time:
static bool alarmed = false;
extern "C" void handler(int signo)
{
alarmed = true;
}
signal(SIGALRM, handler);
alarm(5); // seconds to SIGALRM
// do stuff
// if (alarmed) ...
You could use pthreads start the process and when you don't like your thread anymore you can kill it off with pthread_cancel
pseudo code
start thread
wait
cancel thread if not finished

Calling callback from node.js native code

I'm writing an add-on for node.js using c++.
here some snippets:
class Client : public node::ObjectWrap, public someObjectObserver {
public:
void onAsyncMethodEnds() {
Local<Value> argv[] = { Local<Value>::New(String::New("TheString")) };
this->callback->Call(Context::GetCurrent()->Global(), 1, argv);
}
....
private:
static v8::Handle<v8::Value> BeInitiator(const v8::Arguments& args) {
HandleScope scope;
Client* client = ObjectWrap::Unwrap<Client>(args.This());
client->someObject->asyncMethod(client, NULL);
return scope.Close(Boolean::New(true));
}
static v8::Handle<v8::Value> SetCallback(const v8::Arguments& args) {
HandleScope scope;
Client* client = ObjectWrap::Unwrap<Client>(args.This());
client->callback = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
return scope.Close(Boolean::New(true));
}
I need to save a javascript function as callback to call it later.
The Client class is an observer for another object and the javascript callback should be called from onAsyncMethodEnds.
Unfortunately when I call the function "BeInitiator" I receive "Bus error: 10" error just before the callback Call()
thanks in advice
You cannot ->Call from another thread. JavaScript and Node are single threaded and attempting to call a function from another thread amounts to trying to run two threads of JS at once.
You should either re-work your code to not do that, or you should read up on libuv's threading library. It provides uv_async_send which can be used to trigger callback in the main JS loop from a separate thread.
There are docs here: http://nikhilm.github.io/uvbook/threads.html