Hi folks, I'm working on an external for Max and PD embedding the S7 scheme
interpreter. It's mostly intended to do things at event level, (algo comp,
etc) so I have been somewhat lazy around real time issues so far. But I'd
like to make sure it's as robust as it can be, and can be used for as much
as possible. Right now, I'm pretty sure I'm being a bad real-time-coder.
When the user wants to delay a function call, ie (delay 100 foo-fun), I'm
doing the following:
- callable foo-fun gets registered in a scheme hashtable with a gensym
unique handle
- C function gets called with the handle
- C code makes a clock, storing it in a hashtable (in C) by the handle, and
passing it a struct (I call it the "clock callback info struct") with the
references it needs for it's callback
- when the clock callback fires, it gets passed a void pointer to the
clock-callback-info-struct, uses it to get the cb handle and the ref to the
external (because the callback only gets one arg), calls back into Scheme
with said handle
- Scheme gets the callback out of it's registry and executes the stashed
function
This is working well, but.... I am both allocating and deallocating memory
in those functions: for the clock, and for the info struct I use to pass
around the reference to the external and the handle. Given that I want to
be treating this code as high priority, and having it execute as
timing-accurate as possible, I assume I should not be allocating and
freeing in those functions, because I could get blocked on the memory
calls, correct? I think I should probably have a pre-allocated pool of
clocks and their associated info structs so that when a delay call comes
in, we get one from the pool, and only do memory management if the pool is
empty. (and allow the user to set some reasonable config value of the clock
pool). I'm thinking RAM is cheap, clocks are small, people aren't likely to
have more than 1000 delay functions running concurrently or something at
once, and they can be allocated from the init routine.
My questions:
A) Am I right, both about being bad, and about clock pre-allocation and
pooling being a decent solution?
B) Does anyone have tips on how one should implement and use said clock
pool?
I suppose I should probably also be ensuring the Scheme hash-table doesn't
do any unplanned allocation too, but I can bug folks on the S7 mailing list
for that one...
Thanks!
iain