Some progress.Send calls not making it to nodejs land - c++

I've made a Node addon using AsyncProgressWorker thread to handle my socket messages. Here is my code:
class ProgressWorker : public AsyncProgressWorker {
public:
ProgressWorker(
Callback *callback
, Callback *progress)
: AsyncProgressWorker(callback), progress(progress) {}
~ProgressWorker() {}
void Execute (const AsyncProgressWorker::ExecutionProgress& progress) {
char response[4096];
int result;
int connected = 1;
int timeout = 0;
int pending = 0;
while(connected) {
result = sctp_recvmsg(sock, (void *)&response, (size_t)sizeof(response), NULL, 0, 0, 0);
if (result > 0 && result < 4095) {
if (debug) {
printf("Server replied (size %d)\n", result);
}
pending = 0;
progress.Send((const char *)response, size_t(result));
result = 0;
}
else {
// Don't mind my timeout mechanism. :))
if ((result == -1 && errno != EWOULDBLOCK) || pending) {
if (timeout == 0) {
printf("Can't receive from other end. Waiting for 3 seconds. Error code: %d\n", errno);
pending = 1;
}
if (timeout >= 3000) {
connected = 0;
close(sock);
}
else {
timeout += 5;
usleep(5000);
}
}
else {
usleep(5000);
}
}
}
}
void HandleProgressCallback(const char *data, size_t count) {
HandleScope scope;
v8::Local<v8::Value> argv[] = {
CopyBuffer(const_cast<char*>(data), count).ToLocalChecked()
};
progress->Call(1, argv); // This is the callback to nodejs
}
private:
Callback *progress;
};
Now I haven't stress-tested this until tonight then I noticed that some messages won't make it back to node. It will print my "Server replied" debug log but won't log my debug logs I put on the progress callback. Am I missing something here? Thanks in advance.

AsyncProgressWorker is based on a uv_async_t, which allows any thread to wake the main thread. However, as stated in the documentation:
libuv will coalesce calls to uv_async_send(), that is, not every call
to it will yield an execution of the callback. For example: if
uv_async_send() is called 5 times in a row before the callback is
called, the callback will only be called once. If uv_async_send() is
called again after the callback was called, it will be called again.
^^ This is the reason that you may sometimes not receive some events while your application is under stress. Above this line is the answer to the question. Below is my "above and beyond" possible solution to deal with your problem:
It so happens that I am working on adding a new alternative to AsyncProgressWorker that promises to deliver every event, just as AsyncProgressWorker does, but using a queue. This feature was recently merged into NAN. If you want to test it, try out the git repository at https://github.com/nodejs/nan , and then replace your AsyncProgressWorker with AsyncProgressQueueWorker<char> Re-run your tests and all events will be delivered.
The pull request to add this new feature is here: https://github.com/nodejs/nan/pull/692 - merged on Oct 6, 2017.
This new feature was released in NAN version 2.8.0
You can use this new class template by altering your package.json to use nan version 2.8.0 or later:
"dependencies": {
"nan": "^2.8.0"
},

Related

Using timer with zmq

I am working on a project where I have to use zmq_poll. But I did not completely understand what it does.
So I also tried to implement it:
zmq_pollitem_t timer_open(void){
zmq_pollitem_t items[1];
if( items[0].socket == nullptr ){
printf("error socket %s: %s\n", zmq_strerror(zmq_errno()));
return;
}
else{
items[0].socket = gsock;
}
items[0].fd = -1;
items[0].events = ZMQ_POLLIN;
// get a timer
items[0].fd = timerfd_create( CLOCK_REALTIME, 0 );
if( items[0].fd == -1 )
{
printf("timerfd_create() failed: errno=%d\n", errno);
items[0].socket = nullptr;
return;
}
int rc = zmq_poll(items,1,-1);
if(rc == -1){
printf("error poll %s: %s\n", zmq_strerror(zmq_errno()));
return;
}
else
return items[0];
}
I am very new to this topic and I have to modify an old existing project and replace the functions with the one of zmq. On other websites I saw examples where they used two items and the zmq_poll function in an endless loop. I have read the documentation but still could not properly understand how this works. And these are the other two functions I have implemented. I do not know if it is the correct way to implement it like this:
void timer_set(zmq_pollitem_t items[] , long msec, ipc_timer_mode_t mode ) {
struct itimerspec t;
...
timerfd_settime( items[0].fd , 0, &t, NULL );
}
void timer_close(zmq_pollitem_t items[]){
if( items[0].fd != -1 )
close(items[0].fd);
items[0].socket = nullptr;
}
I am not sure if I need the zmq_poll function because I am using a timer.
EDIT:
void some_function_timer_example() {
// We want to wait on two timers
zmq_pollitem_t items[2] ;
// Setup first timer
ipc_timer_open_(&items[0]);
ipc_timer_set_(&items[0], 1000, IPC_TIMER_ONE_SHOT);
// Setup second timer
ipc_timer_open_(&items[1]);
ipc_timer_set_(&items[1], 1000, IPC_TIMER_ONE_SHOT);
// Now wait for the timers in a loop
while (1) {
//ipc_timer_set_(&items[0], 1000, IPC_TIMER_REPEAT);
//ipc_timer_set_(&items[1], 5000, IPC_TIMER_REPEAT);
int rc = zmq_poll (items, 2, -1);
assert (rc >= 0); /* Returned events will be stored in items[].revents */
if (items [0].revents & ZMQ_POLLIN) {
// Process task
std::cout << "revents: 1" << std::endl;
}
if (items [1].revents & ZMQ_POLLIN) {
// Process weather update
std::cout << "revents: 2" << std::endl;
}
}
}
Now it still prins very fast and is not waiting. It is still waiting only in the beginning. And when the timer_set is inside the loop it waits properly, only if the waiting time is the same like: ipc_timer_set(&items[1], 1000,...) and ipctimer_set(&items[0], 1000,...)
So how do I have to change this? Or is this the correct behavior?
zmq_poll works like select, but it allows some additional stuff. For instance you can select between regular synchronous file descriptors, and also special async sockets.
In your case you can use the timer fd as you have tried to do, but you need to make a few small changes.
First you have to consider how you will invoke these timers. I think the use case is if you want to create multiple timers and wait for them. This would be typically the function in yuor current code that might be using a loop for the timer (either using select() or whatever else they might be doing).
It would be something like this:
void some_function() {
// We want to wait on two timers
zmq_pollitem items[2];
// Setup first timer
ipc_timer_open(&item[0]);
ipc_timer_set(&item[0], 1000, IPC_TIMER_ONE_REPEAT);
// Setup second timer
ipc_timer_open(&item[1]);
ipc_timer_set(&item[1], 5000, IPC_TIMER_ONE_SHOT);
// Now wait for the timers in a loop
while (1) {
int rc = zmq_poll (items, 2, -1);
assert (rc >= 0); /* Returned events will be stored in items[].revents */
}
}
Now, you need to fix the ipc_timer_open. It will be very simple - just create the timer fd.
// Takes a pointer to pre-allocated zmq_pollitem_t and returns 0 for success, -1 for error
int ipc_timer_open(zmq_pollitem_t *items){
items[0].socket = NULL;
items[0].events = ZMQ_POLLIN;
// get a timer
items[0].fd = timerfd_create( CLOCK_REALTIME, 0 );
if( items[0].fd == -1 )
{
printf("timerfd_create() failed: errno=%d\n", errno);
return -1; // error
}
return 0;
}
Edit: Added as reply to comment, since this is long:
From the documentation:
If both socket and fd are set in a single zmq_pollitem_t, the ØMQ socket referenced by socket shall take precedence and the value of fd shall be ignored.
So if you are passing the fd, you have to set socket to NULL. I am not even clear where gsock is coming from. Is this in the documentation? I couldn't find it.
And when will it break out of the while(1) loop?
This is application logic, and you have to code according to what you require. zmq_poll just keeps returning everytime one of the timer hits. In this example, every second the zmq_poll returns because the first timer (which is a repeat) keeps triggering. But at 5 seconds, it will also return because of the second timer (which is a one shot). Its up to you to decide when you exit the loop. Do you want this to go infinitely? Do you need to check for a different condition to exit the loop? Do you want to do this for say 100 times and then return? You can code whatever logic you want on top of this code.
And what kind of events are returned back
ZMQ_POLLIN since timer fds behave like readable file descriptors.

Thread query SDL_Net

Running my listen function in a seperate thread seems to use up a lot of CPU
Is it considered ok to use Delays to reduce cpu usage or am I using threads all wrong ?
// Running in a seperate Thread
void Server::listen()
{
while (m_running)
{
if (SDLNet_UDP_Recv(m_socket, m_packet) > 0)
{
//Handle Packet Function
}
}
}
From the SDLNet_UDP_Recv reference
This is a non-blocking call, meaning if there's no data ready to be received the function will return.
That means if there's nothing to receive then SDLNet_UDP_Recv will return immediately with 0 and your loop will iterate and call SDLNet_UDP_Recv again which returns 0 and so on. This loop will never sleep of pause, so of course it will use as much CPU as it can.
A possible solution is indeed to add some kind of delay or sleep in the loop.
I would suggest something like
while (m_running)
{
int res;
while (m_running && (res = SDLNet_UDP_Recv(...)) > 0)
{
// Handle message
}
if (res < 0)
{
// Handle error
}
else if (m_running /* && res == 0 */)
{
// Small delay or sleep
}
}

czmq asynchronous send/receive (PUB/SUB)

I'm using czmq for interprocess communication.
There are 2 processes :
The server, receiving requests and sending replies but also sending events.
The client, sending requests and receiving replies but also listening to the events.
I have already successfuly implemented the "request/reply" pattern with REQ/REP (details below)
Now I want to implement the notification mechanism.
I want my server to send its events without caring whether anyone receives them or not and without being blocked in anyway.
The client listens to those events but should it crash, it mustn't have any impact on the server.
I believe PUB/SUB is the most appropriate pattern, but if not do not hesitate to enlighten me.
Here's my implementation (cleaned from checks and logs) :
The server publishes the events
Server::eventIpcPublisher = zsock_new_pub("#ipc:///tmp/events.ipc");
void Server::OnEvent(uint8_t8* eventData, size_t dataSize) {
if (Server::eventIpcPublisher != nullptr) {
int retCode = zsock_send(Server::eventIpcPublisher, "b", eventData, dataSize);
}
The client listens to them in a dedicated thread
void Client::RegisterToEvents(const std::function<void(uint8_t*, size_t)>& callback) {
zsock_t* eventIpcSubscriber = zsock_new_sub(">ipc:///tmp/events.ipc", "");
listening = true;
while (listening) {
byte* receptionBuffer;
size_t receptionBufferSize;
int retCode = zsock_recv(eventIpcSubscriber, "b", &receptionBuffer, &receptionBufferSize);
--> NEVER REACHED <--
if (retCode == 0) {
callback(static_cast<uint8_t*>(receptionBuffer), receptionBufferSize);
}
}
zsock_destroy(&eventIpcSubscriber);
}
It doesn't work:
The server sends with return code 0, as if everything is ok,
The client doesn't receive anything (blocked on receive).
Help would be much appreciated, thanks in advance!
Chris.
PS: here is the REQ/REP that I have already implemented with success (no help needed here, just for comprehension)
The client sends a request and then waits for the answer.
uint8_t* MulticamApi::GetDatabase(size_t& sizeOfData) {
zsock_t* requestSocket = zsock_new_req(">ipc:///tmp/requests.ipc");
if (requestSocket == nullptr)
return nullptr;
byte* receptionBuffer;
size_t receptionBufferSize;
int retCode = zsock_send(requestSocket, "i", static_cast<int>(IpcComm_GetClipDbRequest));
if (retCode != 0) {
sizeOfData = 0;
return nullptr;
}
retCode = zsock_recv(requestSocket, "b", &receptionBuffer, &receptionBufferSize);
databaseData.reset(new MallocGuard(static_cast<void*>(receptionBuffer)));
sizeOfData = receptionBufferSize;
return static_cast<uint8_t*>(databaseData->Data());
}
A dedicated thread in the server listens to requests, processes them and replies. (don't worry, delete is handled somewhere else)
U32 Server::V_OnProcessing(U32 waitCode) {
protocolIpcWriter = zsock_new_rep("#ipc:///tmp/requests.ipc");
while (running) {
int receptionInt = 0;
int retCode = zsock_recv(protocolIpcWriter, "i", &receptionInt);
if ((retCode == 0) && (receptionInt == static_cast<int>(IpcComm_GetClipDbRequest))) {
GetDatabase();
}
sleep(1);
}
zsock_destroy(&protocolIpcWriter);
return 0;
}
void Server::GetDatabase() {
uint32_t dataSize = 10820 * 340;
uint8_t* data = new uint8_t[dataSize];
uint32_t nbBytesWritten = DbHelper::SaveDbToBuffer(data, dataSize);
int retCode = zsock_send(protocolIpcWriter, "b", data, nbBytesWritten);
}
I know my question's old but for the record, I switched from czmq to base zmq api and everything went smooth. A colleague of mine also had issues with the czmq layer and switched to zmq to fix them so that's definitely what I recommend.

Sending data in second thread with Mongoose server

I'm trying to create a multithread server application using mongoose web server library.
I have main thread serving connections and sending requests to processors that are working in their own threads. Then processors place results into queue and queue observer must send results back to clients.
Sources are looking that way:
Here I prepare the data for processors and place it to queue.
typedef std::pair<struct mg_connection*, const char*> TransferData;
int server_app::event_handler(struct mg_connection *conn, enum mg_event ev)
{
Request req;
if (ev == MG_AUTH)
return MG_TRUE; // Authorize all requests
else if (ev == MG_REQUEST)
{
req = parse_request(conn);
task_queue->push(TransferData(conn,req.second));
mg_printf(conn, "%s", ""); // (1)
return MG_MORE; // (2)
}
else
return MG_FALSE; // Rest of the events are not processed
}
And here I'm trying to send the result back. This function is working in it's own thread.
void server_app::check_results()
{
while(true)
{
TransferData res;
if(!res_queue->pop(res))
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
continue;
}
mg_printf_data(res.first, "%s", res.second); // (3)
}
}
The problem is a client doesn't receive anything from the server.
If I run check_result function manualy in the event_handler after placing a task into the queue and then pass computed result back to event_handler, I'm able to send it to client using mg_printf_data (with returning MG_TRUE). Any other way - I'm not.
What exactly should I change in this sources to make it works?
Ok... It looks like I've solved it myself.
I'd been looking into mongoose.c code and an hour later I found the piece of code below:
static void write_terminating_chunk(struct connection *conn) {
mg_write(&conn->mg_conn, "0\r\n\r\n", 5);
}
static int call_request_handler(struct connection *conn) {
int result;
conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
if ((result = call_user(conn, MG_REQUEST)) == MG_TRUE) {
if (conn->ns_conn->flags & MG_HEADERS_SENT) {
write_terminating_chunk(conn);
}
close_local_endpoint(conn);
}
return result;
}
So I've tried to do mg_write(&conn->mg_conn, "0\r\n\r\n", 5); after line (3) and now it's working.

Qt timers cannot be stopped from another thread

Hy,
I'm writing my first Qt program and getting now in troubles with:
QObject::killTimer: timers cannot be stopped from another thread
QObject::startTimer: timers cannot be started from another thread
My program will communicate to a CANOpen bus for that I'm using the Canfestival Stack. The Canfestival will work with callback methods. To detects timeout in communication I setup a timer function (somehow like a watchdog). My timer package consist out of a "tmr" module, a "TimerForFWUpgrade" module and a "SingleTimer" module. The "tmr" module was originally C programmed so the static "TimerForFWUpgrade" methods will interface it. The "tmr" module will be part of a C programed Firmware update package.
The timer will work as follows. Before a message is sent I will call TMR_Set method. An then in my idle program loop with TMR_IsElapsed we check for a timer underflow. If TMR_IsElapsed I will do the errorhandling. As you see the TMR_Set method will be called continuously and restart the QTimer again and again.
The above noted errors are appearing if I start my program. Can you tell me if my concept could work? Why does this errors appear? Do I have to use additional threads (QThread) to the main thread?
Thank you
Matt
Run and Idle loop:
void run
{
// start communicate with callbacks where TMR_Set is set continously
...
while(TMR_IsElapsed(TMR_NBR_CFU) != 1);
// if TMR_IsElapsed check for errorhandling
....
}
Module tmr (interface to C program):
extern "C"
{
void TMR_Set(UINT8 tmrnbr, UINT32 time)
{
TimerForFWUpgrade::set(tmrnbr, time);
}
INT8 TMR_IsElapsed(UINT8 tmrnbr)
{
return TimerForFWUpgrade::isElapsed(tmrnbr);
}
}
Module TimerForFWUpgrade:
SingleTimer* TimerForFWUpgrade::singleTimer[NR_OF_TIMERS];
TimerForFWUpgrade::TimerForFWUpgrade(QObject* parent)
{
for(unsigned char i = 0; i < NR_OF_TIMERS; i++)
{
singleTimer[i] = new SingleTimer(parent);
}
}
//static
void TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
if(tmrnbr < NR_OF_TIMERS)
{
time *= TimerForFWUpgrade::timeBase;
singleTimer[tmrnbr]->set(time);
}
}
//static
char TimerForFWUpgrade::isElapsed(unsigned char tmrnbr)
{
if(true == singleTimer[tmrnbr]->isElapsed())
{
return 1;
}
else
{
return 0;
}
}
Module SingleTimer:
SingleTimer::SingleTimer(QObject* parent) : QObject(parent),
pTime(new QTimer(this)),
myElapsed(true)
{
connect(pTime, SIGNAL(timeout()), this, SLOT(slot_setElapsed()));
pTime->setTimerType(Qt::PreciseTimer);
pTime->setSingleShot(true);
}
void SingleTimer::set(unsigned int time)
{
myElapsed = false;
pTime->start(time);
}
bool SingleTimer::isElapsed()
{
QCoreApplication::processEvents();
return myElapsed;
}
void SingleTimer::slot_setElapsed()
{
myElapsed = true;
}
Use QTimer for this purpose and make use of SIGNALS and SLOT for the purpose of starting and stopping the timer/s from different threads. You can emit the signal from any thread and catch it in the thread which created the timer to act on it.
Since you say you are new to Qt, I suggest you go through some tutorials before proceeding so that you will know what Qt has to offer and don't end up trying to reinvent the wheel. :)
VoidRealms is a good starting point.
You have this problem because the timers in the static array is created in Thread X, but started and stopped in Thread Y. This is not allowed, because Qt rely on thread affinity to timeout timers.
You can either create, start stop in the same thread or use signal and slots to trigger start and stop operations for timers. The signal and slot solution is a bit problematic Because you have n QTimer objects (Hint: how do you start the timer at position i?)
What you can do instead is create and initialize the timer at position tmrnbr in
TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
singleTimer[tmrnbr] = new SingleTimer(0);
singleTimer[tmrnbr]->set(time);
}
which is executed by the same thread.
Futhermore, you don't need a SingleTimer class. You are using Qt5, and you already have all you need at your disposal:
SingleTimer::isElapsed is really QTimer::remainingTime() == 0;
SingleTimer::set is really QTimer::setSingleShot(true); QTimer::start(time);
SingleTimer::slot_setElapsed becomes useless
ThusSingleTimer::SingleTimer becomes useless and you dont need a SingleTimer class anymore
I got the errors away after changing my timer concept. I'dont use anymore my SingleTimer module. Before the QTimer I won't let timeout and maybe because of that I run into problems. Now I have a cyclic QTimer that times out every 100ms in slot function I will then count the events. Below my working code:
TimerForFWUpgrade::TimerForFWUpgrade(QObject* parent) : QObject(parent),
pTime(new QTimer(this))
{
connect(pTime, SIGNAL(timeout()), this, SLOT(slot_handleTimer()));
pTime->setTimerType(Qt::PreciseTimer);
pTime->start(100);
}
void TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
if(tmrnbr < NR_OF_TIMERS)
{
if(timeBase != 0)
{
myTimeout[tmrnbr] = time / timeBase;
}
else
{
myTimeout[tmrnbr] = 0;
}
myTimer[tmrnbr] = 0;
myElapsed[tmrnbr] = false;
myActive[tmrnbr] = true;
}
}
char TimerForFWUpgrade::isElapsed(unsigned char tmrnbr)
{
QCoreApplication::processEvents();
if(tmrnbr < NR_OF_TIMERS)
{
if(true == myElapsed[tmrnbr])
{
return 1;
}
else
{
return 0;
}
}
else
{
return 0; // NOK
}
}
void TimerForFWUpgrade::slot_handleTimer()
{
for(UINT8 i = 0; i < NR_OF_TIMERS; i++)
{
if(myActive[i] == true)
{
myTimer[i]++;
if(myTimeout[i] < myTimer[i])
{
myTimer[i] = 0;
myElapsed[i] = true;
myActive[i] = false;
}
}
}
}