Quick note on calling Scheme from C, since I've already covered things the other way around. Rather than some void printing "hello from Scheme" nonsense I wanted to return actual values, but this example may still be incomplete when it comes to complex objects.
(import (chicken foreign))
#>
int cF(int n, int m, int(*schemeF)(int, int)) {
return schemeF(n, m);
}
<#
(define c-f (foreign-safe-lambda int "cF" int int (function int (int int))))
(define-external (adder (int n) (int m)) int (+ n m))
(print (c-f 1 2 (location adder)))
Compile with csc and run the output.
Points of interest:
(foreign-safe-lambda) for some extra bookkeeping.cF taking a function pointer as its argument, it seems like I should specify its parameter type with function rather than c-pointer.(define-external) is used to wrap Scheme code to run in C. Its syntax is odd at first glance, but self-explanatory.adder. It failed to compile as scheme-add, suggesting that Lispy names aren't valid.adder in (location) when calling (c-f). It looks like I can write #$c-f instead as shorthand, but I kept it obvious.See previous notes on inter-thread signaling.
(import (chicken foreign) (srfi-18))
#>
static int TICKS = 0;
void increment(void(*signal)(int)) {
TICKS += 1;
signal(TICKS);
}
<#
(define COND (make-condition-variable))
(define increment (foreign-safe-lambda void "increment" (function void (int))))
(define-external (increment_signal (int n)) void
(begin (condition-variable-specific-set! COND n)
(condition-variable-broadcast! COND)))
(define (c-looper)
(print 'c-loop)
(increment (location increment_signal))
(thread-sleep! 1)
(c-looper))
(define (scheme-looper mutex)
(mutex-lock! mutex)
(print (condition-variable-specific COND))
(mutex-unlock! mutex COND)
(scheme-looper mutex))
(define c-thread (make-thread (lambda () (c-looper))))
(define scheme-thread (make-thread (lambda () (scheme-looper (make-mutex)))))
(thread-start! c-thread)
(thread-start! scheme-thread)
(thread-join! scheme-thread)
Points of interest:
TICKS seem to remain stable and unaffected by garbage collection. There are a lot of ways one could track this, like in the condition variable itself.sleep() inside of C doesn't seem to play nice. As with anything else, I ultimately envision a sndio loop driven by poll() events. Hopefully that works fine.