I’ve been having troubles getting this to work, so any kind of help is appreciated.
As I understand it, from within a C-library function that has been loaded into a running q process, I can call a function in q via sd1(d, f) where d is a file descriptor and f is a q function:
// testlib.c
#include “k.h”
K g(K d, K cb) { return sd1(d->i, cb); }
Is that correct so far? Because when I try to compile the C-code (Win32 free version, under MSVC10 express), I get a link error: “unresolved external symbol _sd1 …” Any help there would be a great start.
The other question is: what file descriptor should I pass into this when I call it from the q side? How do I get such a file descriptor to pass?
That is, if my q-code looks like this,what do I put in place of ???
/ testlib.q
\d .testlib
g:testlib 2:(
g;2)
cbfn:{ 0N!x }
g[???;cbfn]
Thanks,
kov
Hi kov,
sd1 acts like a call back function. It gets triggered when C is trying to communicate with kdb+.
d should be the connection socket to the C server and f is just the function to process the message from C.
I did some work around it if you want to take a look:
http://code.kx.com/wsvn/code/contrib/aquaqanalytics/KDBTCP/?#ab20e72f1a24a6b769ca7df244879e204
Page 14 explain the use of sd1 in my work. You can try to start the C server and q client to see how it works.
Also, you can use sd0 to stop the call back function on the socket.
Hope this will give you a start.
> From c call a function in q
K result=k(handle,“function or function name”,arg0,arg1,
,(K)0);
for an in-process library use handle 0.
e.g.
K result=k(0,“0N!”,ki(42),(K)0);
sd1 is used to trigger callbacks to a c function from the main thread in the q process. It is typically used for interfacing with sockets/feed handlers.
Thanks Kent, so it sounds like sd1/sd0 is not what I need. But I am still curious why I got a link error. Perhaps I was calling sd1 with the wrong # arguments?
kov
Thanks that does help a lot, so now I know that for my case I don’t need sd1/sd0 at all.
I wanted to verify your solution before replying but am getting a segfault, that I can’t resolve. Any other help identifying what else I’m doing wrong greatly appreciated.
// testlib.c
#define KXVER 3
#include “k.h”
K cfn(K cb, K arg) { k(0, cb, arg, (K)0); return (K)0; }
/ testlib.q
cfn:testlib 2:(
cfn;2)
cbfn:{ 0N!x }
cbfn “called directly”
cfn [“cbfn”;“called from C”]
cbfn “done”
Output looks like:
$ q < testlib.q
“called directly”
“called directly”
Sorry, this application or an associated library has encountered a fatal error and will exit.
If known, please email the steps to reproduce this error to tech@kx.com
with a copy of the kdb+ startup banner.
Thank you.
Segmentation fault
Thanks,
kov
K cfn(K cb, K arg) { k(0, cb->s, arg, (K)0); return (K)0; }
sorry, misread.
the 2nd arg to k(0,
should be a null terminated string
and you’ll need to inc ref count on arg.
K cfn(K cb, K arg) { k(0, cb->s, r1(arg), (K)0); return (K)0; }
should work if you call it with
cfn [`cbfn;“called from C”]
this will leak mem as the return value from k(0,.. is not freed.
Good, thanks yet again, added that fix but still getting the segfault. Maybe I’ll try this in Linux, see if this is win32-specific. Is there anything about the eval version that can cause this?
Regards,
kov
usually you can spot memory leaks with .Q.w`used
however this one is quite silent in that it incs the ref count on a constant (::)
visible with
q)-16!(::)
the danger being that the ref count wraps at 2 billion.
Handle the return value from k(0,.. according to the docs at
http://code.kx.com/wiki/Cookbook/InterfacingWithC
Thanks, it’s working now. Calling my C function with `cbfn and refcounting the arg stopped the segfault. I’ll need to look through the documentation on reference counting some more.
For this sample, if I do something like the following will the return value no longer leak?
K cfn(K cb, K arg)
{
K ignored = k(0, cb->s, r1(arg), (K)0);
r0(ignored);
return (K)0;
}
yes, as when using handle 0, there will always be a non-null result.