Page 1 of 1

call back to LCB from C code?

Posted: Sun Mar 08, 2026 8:09 pm
by Emily-Elizabeth
I was wondering if the C code dylib can call back into the LCB?

Re: call back to LCB from C code?

Posted: Sun Mar 08, 2026 9:26 pm
by stam
Emily-Elizabeth wrote:
Sun Mar 08, 2026 8:09 pm
I was wondering if the C code dylib can call back into the LCB?
I really don't know enough about LCB (few here do...)

According to Claude:
Claude AI wrote:Yes, C code in a dylib can call back into LCB, through handler references passed as function pointers.
The mechanism works like this:
On the LCB side, you declare a handler type that matches the C callback signature, then pass an LCB handler as a parameter to the foreign function:

Code: Select all

-- Declare the callback signature
handler type MyCallbackType(in pValue as Integer) returns nothing

-- Declare the foreign function that accepts a callback
foreign handler C_DoSomethingWithCallback(in pCallback as MyCallbackType) \
    returns nothing \
    binds to "c:mylib>DoSomethingWithCallback"

-- Your LCB handler that will be called from C
handler MyCallback(in pValue as Integer)
    -- this runs when C calls back
    log pValue
end handler

-- Wire it up
public handler CallIntoC()
    C_DoSomethingWithCallback(MyCallback)
end handler
On the C side, the dylib receives a plain function pointer it can invoke normally:
ctypedef void (*MyCallbackType)(int value);

void DoSomethingWithCallback(MyCallbackType callback) {
    // Do some work...
    callback(42);  // calls back into LCB
}
Key points to be aware of:

The LCB handler you pass must match the handler type signature exactly
The callback happens synchronously on the same thread — be cautious if your C code calls back from a different thread, as LCB is not thread-safe in that context
If you need asynchronous callbacks (e.g. from a C thread), you'll need to marshal the call back to the main thread, typically by posting a message or using a queue mechanism, which gets considerably more involved
Memory management: the LCB runtime keeps the handler alive as long as the reference exists, but if C holds onto the pointer longer than the LCB side expects, you can get dangling pointer issues

Re: call back to LCB from C code?

Posted: Sun Mar 08, 2026 9:33 pm
by stam
Claude AI wrote: Async callbacks are the tricky case because you cannot call the LCB handler directly from a C thread — it will crash or corrupt state. You need to marshal the call back onto LCB's main thread.
There are two practical approaches:

Option 1: Polling (Simpler)
C side maintains a thread-safe queue. LCB polls it on a timer.

C side:

Code: Select all

#include <pthread.h>
#include <stdlib.h>

// Thread-safe queue
static pthread_mutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER;
static int s_pending_value = 0;
static int s_has_pending = 0;

// Called from background thread
void WorkerThread(void *arg) {
    // ... do async work ...
    int result = 42;
    
    pthread_mutex_lock(&s_mutex);
    s_pending_value = result;
    s_has_pending = 1;
    pthread_mutex_unlock(&s_mutex);
}

// LCB calls this on its timer to drain the queue
int PollForResult(int *out_value) {
    pthread_mutex_lock(&s_mutex);
    int has = s_has_pending;
    if (has) {
        *out_value = s_pending_value;
        s_has_pending = 0;
    }
    pthread_mutex_unlock(&s_mutex);
    return has;
}

LCB side:

Code: Select all

foreign handler C_PollForResult(out pValue as Integer) \
    returns Integer \
    binds to "c:mylib>PollForResult"

handler type MyCallbackType(in pValue as Integer) returns nothing

private variable mCallback as optional MyCallbackType
private variable mTimer as optional Timer

public handler StartAsync(in pCallback as MyCallbackType)
    put pCallback into mCallback
    -- poll every 50ms
    create timer
    set the period of the result to 50
    set the action of the result to MyPollHandler
    put the result into mTimer
end handler

handler MyPollHandler()
    variable tValue as Integer
    if C_PollForResult(tValue) is 1 then
        if mCallback is not nothing then
            mCallback(tValue)
        end if
    end if
end handler


Option 2: MCEngineRunloopScheduleCallback (Cleaner)
The LC engine exposes a function that lets C schedule work onto the main thread's runloop — no polling needed.

C side:

Code: Select all

// Declare the engine's scheduling function
// (available when loaded inside the LC engine process)
typedef void (*MCEngineRunloopCallback)(void *context);
extern void MCEngineRunloopScheduleCallback(
    MCEngineRunloopCallback callback, void *context);

typedef void (*LCBHandlerType)(int value);

typedef struct {
    LCBHandlerType lcb_handler;
    int            value;
} CallbackContext;

// Called on main thread by the engine runloop
static void MainThreadCallback(void *context) {
    CallbackContext *ctx = (CallbackContext *)context;
    ctx->lcb_handler(ctx->value);   // safe — we're on main thread now
    free(ctx);
}

// Called from background thread
void WorkerThread(void *arg) {
    LCBHandlerType handler = (LCBHandlerType)arg;
    
    // ... do async work ...
    int result = 42;
    
    CallbackContext *ctx = malloc(sizeof(CallbackContext));
    ctx->lcb_handler = handler;
    ctx->value       = result;
    
    // Marshal back to main thread
    MCEngineRunloopScheduleCallback(MainThreadCallback, ctx);
}

LCB side:

Code: Select all

handler type MyCallbackType(in pValue as Integer) returns nothing

foreign handler C_StartWorker(in pCallback as MyCallbackType) \
    returns nothing \
    binds to "c:mylib>StartWorker"

public handler StartAsync(in pCallback as MyCallbackType)
    C_StartWorker(pCallback)
    -- no timer needed; engine calls back when ready
end handler

Re: call back to LCB from C code?

Posted: Sun Mar 08, 2026 9:49 pm
by Emily-Elizabeth
Thanks for that. :D

Re: call back to LCB from C code?

Posted: Sun Mar 08, 2026 9:53 pm
by Emily-Elizabeth
Screenshot 2026-03-08 at 12.17.16.png
My latest creation ;)

Re: call back to LCB from C code?

Posted: Sun Mar 08, 2026 10:43 pm
by Emily-Elizabeth
stam wrote:
Sun Mar 08, 2026 9:26 pm
I really don't know enough about LCB (few here do...)
I'm still learning, but have a few extensions on my website.

Re: call back to LCB from C code?

Posted: Mon Mar 09, 2026 11:57 am
by Klaus
Dear Emily-Elizabeth,

thank you very much for all of your work, much appreciated! :-)
Looking forward to whatever you will create in the future.

Best

Klaus

P.S.
Does .nf stand for Norfolk Island, south of Australia?

Re: call back to LCB from C code?

Posted: Mon Mar 09, 2026 12:56 pm
by Emily-Elizabeth
Klaus wrote:
Mon Mar 09, 2026 11:57 am
thank you very much for all of your work, much appreciated! :-)
Looking forward to whatever you will create in the future.
Does .nf stand for Norfolk Island, south of Australia?
Thank you for the kind words. Check out my website for a few goodies that I've already made (just rename the oxtstack to livecodestack).
.NF is the extension code for Norfolk Island.
Seems like it is :) Thanks for teaching me something new! I'm in Canada though, just didn't have many good choices for a free domain name with the host company.

Re: call back to LCB from C code?

Posted: Mon Mar 09, 2026 1:06 pm
by Klaus
Dear Emily-Elizabeth,

of course I already check your site, nice stuff.
Canada not Norfolk Island, OK, get it! :-)

Best

Klaus

Re: call back to LCB from C code?

Posted: Mon Mar 09, 2026 2:07 pm
by Emily-Elizabeth
Klaus wrote:
Mon Mar 09, 2026 1:06 pm
of course I already check your site, nice stuff.
Aren't you full of kind words this morning :oops:
Klaus wrote:
Mon Mar 09, 2026 1:06 pm
Canada not Norfolk Island, OK, get it! :-)
Yeah, the cold and icy place ;)

Re: call back to LCB from C code?

Posted: Mon Mar 09, 2026 5:18 pm
by Klaus
I'm always full of kind words, kudos goes to my mom! :-)

Re: call back to LCB from C code?

Posted: Mon Mar 09, 2026 5:32 pm
by Emily-Elizabeth
Klaus wrote:
Mon Mar 09, 2026 5:18 pm
I'm always full of kind words, kudos goes to my mom! :-)
aww.. Moms are awesome :D