Is there is recommandations, hints on do-do-not-do when ISR requires to allocate dynamic memory?
Can you provide a little more information for me for what the buffer will be used for / what kind of interrupt we're speaking of, so I can provide a better answer ?
(It might also be helpful to know how much RAM you have available).
I usually recommend not to call any routines from within an interrupt.
In my code, allocating memory from interrupts is strictly forbidden.
An interrupt should be serviced quickly, which means it should take only a few nanoseconds to execute, so that the user will never feel the interrupt.
In case it takes a long time, you might get in trouble, because the next interrupt of the same kind may become pending, thus as soon as this interrupt finishes, it will be invoked again.
I understand that you probably don't intend to allocate memory from an interrupt without having to, so my guess is that you probably need the memory for data received via for instance ethernet.
The best way to do this, might be to write your own memory allocator (I did this once for a Web-browser, and it turned out to be blazing fast).
Whether or not it's possible for you to call malloc from within the interrupt, depends on if your malloc is reentrant. If it isn't, then you'll need to roll your own allocator or pre-allocate memory (outside the interrupt) for the data you receive in the interrupt.
If you need only a single buffer of a fixed size, then I highly recommend that you pre-allocate memory when your firmware starts up.
This could be done using a static array for instance.
Depending on your needs, you could also pre-allocate - say - 4 buffers of a fixed size, then the interrupt should not need to do any allocation itself, except from setting a bit, when a buffer is used.
If we're speaking about a UART/USART type of interrupt, then it might be a much better idea to use a FIFO of a fixed size (say 256 bytes), because normally U(S)ARTs are slow and does not transfer a lot of data.
Receiving data on slow U(S)ARTs would usually never cause overflows.
Thanks a lot, you cover it all.
Acctually, I totally agree with "allocating memory from interrupts is strictly forbidden"
In this case, there is rather a lot of accepted 100's bytes that allocating static buffers seems to be not so efficient.
Reading your suggestions, I think I will go with primitive memory allocation service routine.
a nice improvment I'm thinking, might be, that this service will use tresholds,
and will allocate (not as part of the interrupt) more memory chunks from the "normal" dynamic memory allocator library when low water mark pop out...
Thanks a lot!
If your blocks are always 100 bytes, I recommend making a simple super-quick allocator:
1: You make a memory variable (for instance a 32-bit variable), which contains a bit representing a free/used block. This variable will accomodate up to 32 blocks.
2: You make a fixed allocation of 32 x 100 bytes (or 32 x 128 bytes if you have enough memory).
Finding the first free block (for your allocator) can be done very quickly by using the following piece of code:
iBitMask = ~usedBlockMask;
firstFree = ~(iBitMask & ~(iBitMask - 1));
usedBlockMask |= firstFree;
offset = clz(rbit(firstFree));
return(&sFirstBlock[offset * blockSize]);
Above, the CLZ instruction (Count Leading Zeros) is used with the RBIT instruction to form a Count Trailing Zeros; this will give us the position of the first set bit (which in this case is the first cleared bit we've found).
Checking if a block is allocated (for your 'release block' routine) can be done by ...
bitMask = 1 << ((address - sFirstBlock) / blockSize);
if(usedBlockMask & bitMask)
{
usedBlockMask ^= bitMask;
}
else
// block was not previously allocated; report error somehow.
-The above is quick enough for an interrupt. It will be even quicker if you change the block size to 128 instead of 100 bytes, since bit-shifting can then be used.
Almost every OS and bare metal library prohibit such things in an ISR and for very good reason. If you need to fill in a buffer or something in an ISR, make sure it is allocated beforehand and the address accessible to the ISR.
Problems:
1. What do you do in case of allocation failure?
2. ISRs are supposed to do two, and only two, thing: Stop the hardware from interrupting and schedule post processing in normal context. To do anything else risks severely degrading the performance and reliability of the system.
3. Most calls, like allocating memory, requires some sort of process context. An ISR has no such context, unless it is bare metal.
Potential solutions:
1. Rotating buffers.
2. Pre-allocated single buffer
3. Allocate and copy data in post processing AFTER the HW interrupt has been acknowledged and system interrupts reenabled.
One more solution:
Process the data inside the interrupt, in case processing the data will be quick.