问题描述:

I have an external C-library for asynchronously consuming data via callback functions on a background thread; I want to receive the data and process it in a q process. Following code.kx.com's Interfacing with C documentation, I made a small C-library of glue code converting the inbound source data into k structures and dispatching it to my q process vi sd1/sd0 calls so that the q function gets invoked on q's thread context. The program successfully invokes the initial callback then hangs.

I've stripped down the program to what I think is the bare minimum to simply demonstrate a C BG-thread callback into a q function, but I'm not sure if I've stripped away too much. For example, sd1 accepts a FD and a C-callback. My bare minimum FD is created via eventfd(), which is used for subsequent sd1/sd0 calls. I have tried invoking read and write on the FD, and not doing any IO over the FD, either way the program hangs.

Here's my bare-bones C-library:

/* testlib.c */

#define KXVER 3

#include "k.h"

#include <pthread.h>

#include <sys/eventfd.h>

I d;

pthread_t tid;

K qdisp(I d)

{

K ignored = k(0, (S)"onCB", kj(54321), (K)0);

sd0(d);

return (K)0;

}

void* loop(void* vargs)

{

while(1) {

sleep(1);

sd1(d, qdisp);

}

return NULL;

}

K init(K ignore)

{

d = eventfd(1, 0);

int err = pthread_create(&tid, NULL, &loop, NULL);

return (K)0;

}

And here's the q script that invokes it:

/ testlib.q

init:`testlib 2:(`init;1)

onCB:{ 0N!x }

init[`blah]

Any tips or comments appreciated.

网友答案:

Are you sure the other side provides enough data? As I see from the documentation referenced by you, communication is done by using blocking pipes. This means that if there is not enough data, or the buffer is not flushed by the producer, you application should block and this is its intended behavior.

You could try to use sd0()/sd1() skipping the d parameter to verify that the observed behavior is caused by blocking pipe and not by something else.

网友答案:

For those interested, it looks like sd1 schedules a function to be invoked every time there is data available to be read on a file descriptor, and sd0 removes the scheduled function from invocation.

So the idea is to write a function that attempts to read from the FD; if successful, invoke your q function via k() and return the result, if 0 just return 0, and if error call sd0.

#define KXVER 3
#include "k.h"
#include <pthread.h>
#include <sys/eventfd.h>
#include <stdio.h>
I d;
pthread_t tid;
K qdisp(I d)
{
    J v;
    if (-1 != read(d, &v, sizeof(J)) ) {
        return k(0, "onCB", ki(v), (K)0);
    }
    sd0(d);
    return (K)0;
}
void* loop(void* vargs)
{
    J j = 0;
    sd1(d, qdisp);
    while(j++) {
        sleep(1);
        write(d, &j, sizeof(J));
    }
    return NULL;
}
K init(K cb)
{
    d = eventfd(1, 0);
    int err = pthread_create(&tid, NULL, &loop, NULL);
    return (K)0;
}
相关阅读:
Top